Gre*_*reg 5 regex excel m powerquery powerbi
我希望在 Power Query (M) for Excel 中执行正则表达式检测(和匹配?),它缺乏对正则表达式的本机支持。与 Power BI 不同,Excel 缺乏与 R 和 Python 的集成,因此我无法使用它们来外包正则表达式操作。
\n受到u/tirlibibi17这个巧妙 hack 的启发,我通过将 M 与 JavaScript (JS) 及其正则表达式功能集成,概括了一个本机解决方案。请参阅下面的解决方案部分以了解我的完整工作。
\n虽然我已经成功地Rgx_Test()在单个text字符串上进行了测试,但它在规模上陷入了困境,因为它Web.Page()为每个正在测试的字符串重新生成了 。对于复数,我渴望一次性对一批许多这样的字符串Rgx_Tests()进行操作。
我的“预期脚本”Rgx_Tests()应该改进 的“当前脚本” Rgx_Test()。M 中的原生Json.*()系列有助于与 JS 脚本交换批量数据,如 JSON 表示法所示。对于输入,M 中的a listof s 变为JS 中的an of s。对于输出,JS 中的an of s 变为M 中的a of s。textArrayStringArrayBooleanlistlogical
不幸的是,一次神秘的失败打断了我的进步Rgx_Tests():
虽然我当前的脚本正确渲染了Booleanvia document.write(),但我预期的脚本无法同样渲染StringJSON 文本。这String是由JSON.stringify()生成Array的Boolean生成的。
此问题仅出现在 M 中,而不出现在 JS 中,如单独的预期脚本所示(如下)。大概错误在于Web.Page(),但为什么它应该渲染 aBoolean却无法渲染 aString?
不会抛出任何错误。当前脚本将 呈现Boolean在文本块中,我可以在其中轻松找到它。对于预期的脚本,这个文本块只是丢失了。
有关详细信息,请参阅下面的调试部分。
\n这种神秘故障的根源是什么?我该如何解决它?
\n我确实知道 JS 脚本在语法或运行时有错误,会产生这种行为。然而,该 JS 脚本(如下)可以完美地自行运行。 也许类似的函数JSON.stringify()与 M 使用的 JS 版本不兼容?
Rgx_Test()我当前的脚本运行顺利,并呈现原始文本供 M 解释为logical.
我采用 M 中的单个text字符串,并通过我的助手将其转换Json_Stringify()......
Json_Stringify("A1")\nRun Code Online (Sandbox Code Playgroud)\n...进入其 JSON 表示形式...
\n"A1"\nRun Code Online (Sandbox Code Playgroud)\n...我将其“注入”(拼接)到下面的 JS 脚本中。
\n<html><body><script>\n // \xcb\x87\xcb\x87\xcb\x87\xcb\x87\n var txt = "A1";\n // ^^^^\n var ptn = "[a-z]\\\\d";\n var flg = "i";\n var rgx = new RegExp(ptn, flg);\n var tst = rgx.test(txt);\n document.write(tst);\n</script></body></html>Run Code Online (Sandbox Code Playgroud)\r\n它将结果呈现为原始文本......
\ntrue\nRun Code Online (Sandbox Code Playgroud)\n...我通过它钻取和提取Web.Page():

然后我通过解析它Logical.FromText()然后我通过...
Logical.FromText("true")\nRun Code Online (Sandbox Code Playgroud)\n...产生一个logical结果。
true\nRun Code Online (Sandbox Code Playgroud)\nRgx_Tests()我渴望下面的脚本,它在 JS 中成功,但无法渲染 JSON 文本以供 M 解释为listoflogical s。
我在 M 中取一个listof texts,并通过我的助手将其转换Json_Stringify()......
Json_Stringify({"A1", "2b", "c_3", "d4_"})\nRun Code Online (Sandbox Code Playgroud)\n...进入其 JSON 表示形式...
\n["A1","2b","c_3","d4_"]\nRun Code Online (Sandbox Code Playgroud)\n...我将其“注入”(拼接)到下面的 JS 脚本中:
\n<html><body><script>\n // \xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\n var txts = ["A1","2b","c_3","d4_"];\n // ^^^^^^^^^^^^^^^^^^^^^^^\n var ptn = "[a-z]\\\\d";\n var flg = "i";\n var rgx = new RegExp(ptn, flg);\n function rgx_test(txt) {return rgx.test(txt)};\n var tsts = txts.map(rgx_test);\n var out = JSON.stringify(tsts);\n document.write(out);\n</script></body></html>Run Code Online (Sandbox Code Playgroud)\r\n它应该将结果呈现为(JSON)文本......
\n[true,false,false,true]\nRun Code Online (Sandbox Code Playgroud)\n...我可以通过它钻取和提取Web.Page():

然后我可以通过解析Json.Document()然后我可以通过...
Json.Document("[true,false,false,true]")\nRun Code Online (Sandbox Code Playgroud)\n...产生list一个logical。
{true, false, false, true}\nRun Code Online (Sandbox Code Playgroud)\nrecord不幸的是,该文本块的对应内容在输出中完全不存在tableWeb.Page():

Rgx_Tests()这应该针对正则表达式测试list字符串,并返回textpatternlistlogical。
let Rgx_Tests = (\n texts as list,\n pattern as text,\n optional insensitive as nullable logical\n) as nullable list =>\n let\n txts = Json_Stringify(texts),\n ptn = Json_Stringify(pattern),\n flg = Json_Stringify(Rgx_Flags(false, false, insensitive)),\n \n html = "<html><body><script>\n var txts = " & txts & ";\n var ptn = " & ptn & ";\n var flg = " & flg & ";\n var rgx = new RegExp(ptn, flg);\n function rgx_test(txt) {return rgx.test(txt)};\n var tsts = txts.map(rgx_test);\n var out = JSON.stringify(tsts);\n document.write(out);\n </script></body></html>",\n \n page = Web.Page(html),\n out = page{0}[\n Data\n ]{[\n Name = "HTML"\n ]}[Children]{[\n Name = "BODY"\n ]}[Children]{[\n Kind = "Text"\n ]}[\n Text\n ],\n \n result = try Json.Document(out) otherwise null\n in\n result\nin\n Rgx_Tests\nRun Code Online (Sandbox Code Playgroud)\n这是我目前执行的功能。
\nRgx_Flags()该助手生成正则表达式标志字符串为 JS
\nlet Rgx_Flags = (\n optional hasIndices as nullable logical,\n optional global as nullable logical,\n optional ignoreCase as nullable logical,\n optional multiline as nullable logical,\n optional dotAll as nullable logical,\n optional unicode as nullable logical,\n optional unicodeSets as nullable logical,\n optional sticky as nullable logical\n) as text =>\n let\n MOD_SEP = "",\n MOD_NOT = "",\n MOD_FLAGS = [\n hasIndices = "d",\n global = "g",\n ignoreCase = "i",\n multiline = "m",\n dotAll = "s",\n unicode = "u",\n unicodeSets = "v",\n sticky = "y"\n ],\n \n ind = if hasIndices = true then MOD_FLAGS[hasIndices] else MOD_NOT,\n glo = if global = true then MOD_FLAGS[global] else MOD_NOT,\n ign = if ignoreCase = true then MOD_FLAGS[ignoreCase] else MOD_NOT,\n mul = if multiline = true then MOD_FLAGS[multiline] else MOD_NOT,\n dot = if dotAll = true then MOD_FLAGS[dotAll] else MOD_NOT,\n uni = if unicode = true then MOD_FLAGS[unicode] else MOD_NOT,\n uns = if unicodeSets = true then MOD_FLAGS[unicodeSets] else MOD_NOT,\n sti = if sticky = true then MOD_FLAGS[sticky] else MOD_NOT,\n \n result = Text.Combine({ind, glo, ign, mul, dot, uni, uns, sti}, MOD_SEP)\n in\n result\nin\n Rgx_Flags\nRun Code Online (Sandbox Code Playgroud)\nJson_Stringify()这个助手将一个value为其 JSON 表示形式。
let Json_Stringify = (\n value as any,\n optional encoding as nullable number\n) as nullable text =>\n Text.FromBinary(Json.FromValue(value, encoding), encoding)\nin\n Json_Stringify\nRun Code Online (Sandbox Code Playgroud)\nRgx_Test()text这针对正则表达式测试单个字符串pattern,并返回logical结果。
let Rgx_Test = (\n text as text,\n pattern as text,\n optional insensitive as nullable logical\n) as nullable logical =>\n let\n txt = Json_Stringify(text),\n ptn = Json_Stringify(pattern),\n flg = Json_Stringify(Rgx_Flags(false, false, insensitive)),\n \n html = "<html><body><script>\n var txt = " & txt & ";\n var ptn = " & ptn & ";\n var flg = " & flg & ";\n var rgx = new RegExp(ptn, flg);\n var tst = rgx.test(txt);\n document.write(tst);\n </script></body></html>",\n \n page = Web.Page(html),\n tst = page{0}[\n Data\n ]{[\n Name = "HTML"\n ]}[Children]{[\n Name = "BODY"\n ]}[Children]{[\n Kind = "Text"\n ]}[\n Text\n ],\n \n result = try Logical.From(tst) otherwise null\n in\n result\nin\n Rgx_Test\nRun Code Online (Sandbox Code Playgroud)\n
在@DavideBacci的帮助下,我找到了一个相当稳定的解决方案。
\nWeb.Page()仅使用一次而不是针对texts.JSON.stringify(),正如我自己在这里诊断的那样。\'|\'),否则必须对其进行解析。Rgx_Tests_2()使用原始帮助程序Json_Stringify()和Rgx_Flags(),此改进Rgx_Tests()实际上适用于 Power Query。
let Rgx_Tests_2 = (\n texts as list,\n pattern as text,\n optional insensitive as nullable logical\n) as nullable list =>\n let\n // Constants.\n JS_NEW = "#(lf)",\n HTML_TAG = "<br>",\n \n // Workflow.\n result = if List.IsEmpty(texts) then\n {}\n else\n let\n strs = List.Transform(texts, Json_Stringify),\n ptn = Json_Stringify(pattern),\n flg = Json_Stringify(Rgx_Flags(null, null, insensitive)),\n tag = Json_Stringify(HTML_TAG),\n \n lines = List.Transform(strs, each\n "document.write(tag + rgx.test(" & _ & "));"\n ),\n code = Text.Combine(lines, JS_NEW),\n \n html = "<html><body><script>\n var ptn = " & ptn & ";\n var flg = " & flg & ";\n var tag = " & tag & ";\n var rgx = new RegExp(ptn, flg);\n " & code & "\n </script></body></html>",\n \n page = Web.Page(html),\n out = page{0}[Data]{[\n Name = "HTML"\n ]}[Children]{[\n Name = "BODY"\n ]}[Children],\n exprs = Table.SelectRows(out, each [Kind] = "Text")[Text],\n \n lgls = try List.Transform(exprs, Logical.FromText) otherwise null\n in\n lgls\n in\n result\nin\n Rgx_Tests_2\nRun Code Online (Sandbox Code Playgroud)\nRgx_Tests_2()我在 M 中取一个listof texts,并通过我的助手将它们表示为 JS 文字Json_Stringify():
List.Transform({"A1", "2b", "c_3", "d4_"}, Json_Stringify)\nRun Code Online (Sandbox Code Playgroud)\n然后我把.Transform()它们分成几行代码,将.write()它们的.test()结果发送到页面,然后将.Combine()它们分成一个块......
document.write(tag + rgx.test("A1"));\ndocument.write(tag + rgx.test("2b"));\ndocument.write(tag + rgx.test("c_3"));\ndocument.write(tag + rgx.test("d4_"));\nRun Code Online (Sandbox Code Playgroud)\n...我将其“注入”(拼接)到下面的 JS 脚本中:
\n<html><body><script>\n var ptn = "[a-z]\\\\d";\n var flg = "i";\n var tag = "<br>";\n var rgx = new RegExp(ptn, flg);\n \n // \xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\xcb\x87\n document.write(tag + rgx.test("A1"));\n document.write(tag + rgx.test("2b"));\n document.write(tag + rgx.test("c_3"));\n document.write(tag + rgx.test("d4_"));\n // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n</script></body></html>Run Code Online (Sandbox Code Playgroud)\r\n它将结果呈现在单独的纯文本块中......
\n\n\n真的
\n
\n\n错误的
\n
\n\n错误的
\n
\n\n真的
\n
...我通过钻取和提取Web.Page()。

Logical.FromText()最后我通过...解析
List.Transform({"true", "false", "false", "true"}, Logical.FromText)\nRun Code Online (Sandbox Code Playgroud)\n...产生一系列list结果logical。
{true, false, false, true}\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
239 次 |
| 最近记录: |