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/b74e95d607a1b0717fd5360c
ba1aa81144318f9a.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'。如果当前行的文本为其他值,就会进行该值替换自身的操作。
- 个人感觉最佳的两种写法:
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'
回复
- 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