新浪博客

powerquery批量替换自定义函数

2022-05-08 09:14阅读:
原列 其它列 原值 替换为
我喜欢你 张三
你对她说了什么 李四
她说不认识我 王五

结果:

原列 其它列
张三喜欢李四
李四对王五说了什么
王五说不认识张三
张三
李四

https://cloud.tencent.com/developer/article/1603738
(三) 代码书写(这个适合字符串局部替换)
List.Accumulate(List.Zip({origian_list,replace_list}),
table, //操作的表
(x,y)=>Table.ReplaceValue(x,
y{0}, //原值
y{1}, //替换值
Replacer.ReplaceText, //文本替换函数
{column_name} //需要替换的列名
)
)
复制
解释:
通过List.Zip构建一个新旧值交叉组合成的列表;
x代表的是table(需要操作的表);
y代表的是交叉组合成的列表,其中y{0}代表的是组合交叉列表中的第一个值,也就是原值,y{1}代表的是组合交叉列表中的第二个值,也就是替换值;
因为涉及到文本替换,所以使用的是Replacer.ReplaceText;
最后是需要替换的列名,需要文本格式。
在左侧的句中右侧的对照表批量替换单词。(这个适合有间隔符间隔的,整体替换或单字符替换)
Power Query提供了丰富的函数来进本处理,我们系统提供的函数就可以完成单词替换,需要了解下四个函
数:
•List.ReplaceMatchingItems
•Text.SplitAny
•Text.Combine
•Table.ToRows
List.ReplaceMatchingItems
这个函数是实现批量替换的核函数,需要两个参数:
原列表:把句拆分成单词列表
替换列表:把替换单词对照表,转换成需要的列表,替换列表的结构是个样的
{{原单词,替换单词},{原单词,替换单词},{原单词,替换单词},,,,}
=Text.Combine(
List.ReplaceMatchingItems(
Text.SplitAny([Text],' '),
Table.ToRows(Replacements)),
' ')
--------------------------------------------------------
作者:谷梁耘涛资料集合分享
链接:https://wenku.baidu.com/view/b74e95d607a1b0717fd5360cba1aa81144318f9a.html
来源:百度文库
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
https://pqfans.com/3619.html
在某些办公情景中,有时需要把同一列的多个文本替换成新的文本。假设现在需要把如下表格ProductList中Product列的'A(ii)', 'B(ii)'以及'C(ii)'分别替换成'A', 'B'以及'C':
对于这个问题,最直接的解决办法是进行三次常规替代,以下为该思路的代码: let Step1 = Table.ReplaceValue( ProductList, 'A(ii)', 'A', Replacer.ReplaceText, {'Product'} ), Step2 = Table.ReplaceValue( Step1, 'B(ii)', 'B', Replacer.ReplaceText, {'Product'} ), Step3 = Table.ReplaceValue( Step2, 'C(ii)', 'C', Replacer.ReplaceText, {'Product'} ) in Step3
如果需要被替换的值不止三种,代码的长度可能就会变得十分长。在《发票号展开》中,施阳老师已经介绍过如何使用List.Accumulate()化简高度相似的重复代码,以下为沿用该思路的代码:
let ToRows = Table.ToRows( Parameter ), Outcome = List.Accumulate( ToRows, ProductList, (x, y) Table.ReplaceValue( x, y{0}, y{1}, Replacer.ReplaceText, {'Product'} ) ) in Outcome
以下为代码中Parameter表格的图像:
代码中的ToRows步骤,把Parameter表格转化为{{'A(ii)', 'A'}, {'B(ii)', 'B'}, {'C(ii)', 'C'}},此结果将会被用作List.Accmulate()的第一个参数。然后在下一步中,List.Accumulate会对ProductList进行Text.ReplaceValue操作,把Product列中所有的'A(ii)'替换成'A'。List.Accumulate()会对替换文本后的表格再进行类似的操作把'B(ii)'和'C(ii)'分别替换为'B'和'C'。


除了以上思路,其实还可以利用记录(Record)的特点解决以上问题,以下为第二种思路的代码(只能做整体替换): let TableToCols = Table.ToColumns( Parameter ), ListToRecord = Record.FromList( TableToCols{1}, TableToCols{0} ), Outcome = Table.ReplaceValue( ProductList, each [Product], each Record.FieldOrDefault( ListToRecord, [Product], [Product] ), Replacer.ReplaceText, {'Product'} ) in Outcome
要理解第二种思路,首先要了解由Parameter表格转化而来的ListToRecord,以下为ListToRecord的截图:
上图说明了ListToRecord其实是文本旧值与新值存在一一对应关系的数据结构。利用ListToRecord,如果当前行的文本为'A(ii)', 'B(ii)'或者'C(ii)',就会被分别替换为'A', 'B'或者'C'。如果当前行的文本为其他值,就会进行该值替换自身的操作。






  1. 个人感觉最佳的两种写法:
    let
    //添加列这样写比较直观,而且可以在内置界面里编辑,缺点是不能部分替换和多重替换
    #'Added Custom' = Table.AddColumn(ProductList, 'Custom', each Record.FieldOrDefault(
    [
    #'A(ii)'='A',
    #'B(ii)'='B',
    #'C(ii)'='C'
    ],
    [Product],[Product]))
    ,
    //自建replacer接受list做为需要替换的多个字符,这里用内嵌函数,也可以写成公共函数来调用
    ReplaceMultText = (inputText, oldValues, newValues, optional i) =>
    let
    i = if (i = null) then 0 else i,
    outputText =
    if i < List.Count(oldValues) then
    //递归调用,也可以写成循环
    @ReplaceMultText(
    Replacer.ReplaceText(inputText,oldValues{i},newValues{i}),
    oldValues,newValues,i+1)
    else inputText
    in
    outputText,
    //通过参数类型可以看出Table.ReplaceValue已经预留了扩展空间
    //Table.ReplaceValue(table as table, oldValue as any, newValue as any, replacer as function, columnsToSearch as list) as table
    #'Replaced Value' = Table.ReplaceValue(
    #'Added Custom',
    {'A(ii)','B(ii)','C(ii)'}, //oldValue、newValue类型是any,实际是传给replacer处理
    {'A','B','C'}, // 这里用list把需要替换的多个字符传给replacer
    ReplaceMultText, //这个参数改为调用自建的replacer
    {'Product'}
    )
    in
    #'Replaced Value'
    回复
  2. Andrew说道:
    2020年11月11日 上午11:11
    刚才有递归试了下,也可以!
    let
    Source = ProductList,
    A = Table.ToRows(Parameter),
    //Tolist = List.Transform(Table.ToColumns(Source){0},each Text.Replace(_,A{2}{0},A{2}{1})),
    Len = List.Count(A),
    MyFun =(n)=> if n = 1 then List.Transform(Table.ToColumns(Source){0}, each Text.Replace(_,A{0}{0},A{0}{1})) else
    List.Transform(@MyFun(n-1),each Text.Replace(_,A{n-1}{0},A{n-1}{1})),
    B = MyFun(Len)
    in
    B
    回复









示例下载:
链接: https://pan.baidu.com/s/1wGSQGmYn1bsHpccm7uzpxw?pwd=hhz9 提取码: hhz9

我的更多文章

下载客户端阅读体验更佳

APP专享