一直沒能說服公司小伙伴不要用合并單元格,因此我接收到的原始表格總是充滿了各種合并單元格。最頭痛的是列名有合并的。比如下面這樣的(且不說這難看的屎黃):

列名有合并單元格也就罷了,關(guān)鍵是這合并單元格也是動(dòng)態(tài)的——不同時(shí)間提交過來的表格,合并單元格的具體內(nèi)容會(huì)有變化。真是整死個(gè)人么也幺哥,整死個(gè)人么也幺哥……
目前總結(jié)了四種方法:
一、釜底抽薪法
最牛逼最有效的當(dāng)然是說服提供表格的小伙伴停止使用坑爹的合并單元格(以及莫名其妙的底紋)。
二、自己辛苦手動(dòng)修改法
就是每次收到excel表格后,我自己手動(dòng)取消合并單元格,把列名整理成合規(guī)的格式。
但作為一個(gè)超級(jí)懶人,每次來了一個(gè)表格都要手動(dòng)改半天,太不優(yōu)雅了。于是有了第三種方法。
三、利用list.zip()函數(shù)合成重命名列名表達(dá)式法
用powerquery大法,引入數(shù)據(jù)源后,合并單元格會(huì)被打散。以下是關(guān)鍵步驟:
1.將合并單元格的第一行提升為表格標(biāo)題,這樣一來,之前是合并單元格的列名會(huì)變成類似于“column5”、“column6”之類的,其他都是正常的列名。而第二行的數(shù)據(jù),正常列名下面的值變成了null,以“columnX”開頭的列下面是我們要提取出來的列名,如截圖中“投放媒體”下面的四個(gè)值。
2.利用powerquery訪問行的方法,得到表格第一行的值,基本函數(shù)是Record.FieldValues()。
3.然后將第二步得到的list和Table.ColumnNames()函數(shù)獲取的表格列名用List.Zip()函數(shù)進(jìn)行合并,得到一個(gè)包含list的list,為敘述方便,將其命名為M。這時(shí)用List.Transform(M,Combiner.CombineTextByDelimiter(""))將M中每個(gè)子list的元素合并成一個(gè),這樣我們就得到一個(gè)近似于完美的目標(biāo)表格列名。之所以說,近似完美,是因?yàn)镸進(jìn)行這樣的變換后(命名為MM),其中包含“Column6百度信息流作”這樣的元素,我們需要將“Column6”這樣的字母和數(shù)字去掉,只保留文本。
4.于是用List.Transform(MM,each Text.Remove(_,List.Union({{"A".."z"},{"0".."9"}})))將數(shù)字和字母去掉,保留中文。
5.這樣我們就得到一個(gè)TargetColumnName的list。再次用List.Zip()函數(shù)構(gòu)造重命名列名的表達(dá)式:Table.RenameColumns(table,List.Zip({OriginalColumnName,TargetColumnName}))。
6.這樣就基本完成了表格的重命名工作。不過還留下了一個(gè)小尾巴,就是“投放媒體”對(duì)應(yīng)索引位置的第二行值是類似于“網(wǎng)站制作”這樣的,所以最后還要把“投放媒體”這樣的批量替換掉。
這個(gè)方法繁瑣且留有尾巴,我還是想找一個(gè)更優(yōu)雅的辦法來解決合并單元格動(dòng)態(tài)命名的問題。于是有了終極大法。
四、終極大法:Table.TransformColumnNames()函數(shù)大法
這個(gè)函數(shù)太復(fù)雜,我也沒完全搞懂,主體結(jié)構(gòu)是:
Table.TransformColumnNames(table as table, nameGenerator as function, optional options as nullable record) as table
爬網(wǎng)并試驗(yàn),最后得出了下面的這個(gè)表達(dá)式:
Table.TransformColumnNames(#"Promoted Headers",each
if
Text.Contains(_,"Column")
then
Record.FieldValues(#"Promoted Headers"{0}){(List.PositionOf(Table.ColumnNames(#"Promoted Headers"),_))}
else
if _="投放媒體"
then
Record.FieldValues(#"Promoted Headers"{0}){(List.PositionOf(Table.ColumnNames(#"Promoted Headers"),_))}
else _
)
超級(jí)長(zhǎng)的一行代碼,我的思路是,利用if...then...else結(jié)構(gòu),逐一判斷表格列名的每一個(gè)元素是否包含“Column”,如果包含,那么它就是需要變換的列名,如果不包含,那么就(暫時(shí))不做任何操作。
那么,怎么變換呢?還是最基礎(chǔ)的思路,用列名對(duì)應(yīng)的表格第一行的值來代替。怎么知道當(dāng)前列名的索引位置是多少呢?用List.PositionOf()來獲取。獲取到索引位置后,就很簡(jiǎn)單了,用Table{0}{索引位置}就可以得到列名對(duì)應(yīng)的第一行的值。
完成。