powerbi - Regexp a Power Query-ben JavaScript használatával
Szükségem van reguláris kifejezésekre, míg az M/Power Query natív támogatással nem rendelkezik hozzá. Találtam többféle megoldást ugyanarra a kiváló Web.Page & JavaScript ötletre - Biccauntant, Hugoberry.
El kellett fogadnom őket (az eredményül kapott kód alább található) a JavaScript korlátai miatt.
A fő probléma az, hogy a JavaScript-nek megvan a saját kemény korlátja a String változókon - nem lehetséges használni benne a "\" karaktert.
Az én változatom kezeli a problémát, de nem vagyok profi JS-ben, szóval a fő kérdés az - gyanítom, hogy a "\" probléma nem az egyetlen.
Tehát a kérdésem az, hogy - lát valaki más problémákat a PQ és a JavaScript „együttműködésében”, miközben a reguláris kifejezést használja? Más buktatókkal kapcsolatban a karakterláncokkal vagy bármi mással kapcsolatban?
Értem, hogy a Regexp-nek megvannak a saját escape szabályai (ez nemcsak a JavaScript követelménye, hanem magáé a Regexp-é is), így a Regex saját magára vonatkozó escape-elése kívül esik a kérdés hatáskörén. Vagyis a reguláris kifejezést megfelelően le kell escape-elni, MIELŐTT mint függvényparaméter átadható lenne. Más szóval, feltételezzük, hogy ha a felhasználó reguláris kifejezést akar használni "\" karakterrel, akkor helyette "\\"-t kell használnia, és a függvényem ezt ""\"-re fogja konvertálni, amelyet a JavaScript Regexp kifejezésként fogad el.
PQ felhasználóknak - kiderült, hogy a megoldás teljesítménye legalább több száz sor esetén egészen jó. De ne felejtsük el, hogy a funkciót a Power BI szolgáltatásban nem lehet használni, ez csak a Power BI Desktophoz és az Excelhez alkalmas.
A kód:
(text as nullable text, pattern as nullable text) as logical =>
let
l = List.Transform({text, pattern}, each Text.Replace(_, "\", "\\")),
t = Text.Format("<script>document.write(new RegExp('#{1}').test('#{0}'))</script>", l),
w = Web.Page(t),
d = w[Data]?{0}?[Children]?{0}?[Children]?{1}?[Text]?{0}?,
result = text <> null and (pattern = null or (if d <> null then Logical.FromText(d) else error "Regular expression or text are not supported by JavaScript."))
in
resultVálasz #1
A fenti kód alapján (és az aposztrófok ' helyes elkerülésével) a következő függvényeket javaslom (3 függvényt tartalmazok, egyet a teszteléshez, egyet az egyezéshez és egyet a cseréhez).
MEGJEGYZÉS: Van egy probléma, amit nem tudok megoldani. A megfeleltetési függvényben a visszaadott lista hibás lesz, ha a karakterlánc vagy a találatok vesszőt (',') tartalmaznak. Megpróbáltam a JSON.stringify() használatát a találatok kiíratásához, de ez nem működik, itt felteszek egy kérdést erről, és később megpróbálom javítani, ha lehetséges.
Függvény reguláris kifejezés teszteléséhez
// regexTest
let regexTest=(text as nullable text,replace as nullable text, optional flags as nullable text) as logical =>
let
f= if flags = null or flags ="" then "" else flags,
l1 = List.Transform({text, replace}, each Text.Replace(_, "\", "\\")),
l2 = List.Transform(l1, each Text.Replace(_, "'", "\'")),
l3 = List.Combine({l2,{f}}),
t = Text.Format("<script>document.write(new RegExp('#{1}','#{2}').test('#{0}'))</script>", l3),
r = Web.Page(t)[Data]{0}[Children]{0}[Children]{1}[Text]{0},
Output = Logical.From(r)
in Output
in regexTest
Függvény reguláris kifejezés illesztéshez
// regexMatch
let regexMatch=(text as nullable text, pattern as nullable text, optional flags as nullable text) as list =>
let
f=if flags = null or flags ="" then "" else flags,
l1 = List.Transform({text, pattern}, each Text.Replace(_, "\", "\\")),
l2 = List.Transform(l1, each Text.Replace(_, "'", "\'")),
t = Text.Format("<script>var txt='#{0}';document.write(txt.match(new RegExp('#{1}','#{2}')));</script>", List.Combine({l2,{f}})),
r=Web.Page(t)[Data]{0}[Children]{0}[Children],
Output=if List.Count(r)>1 then Text.SplitAny(r{1}[Text]{0},",") else {}
in Output
in regexMatch
Függvény reguláris kifejezés cseréhez
// regexReplace
let regexReplace=(text as nullable text,pattern as nullable text,replace as nullable text, optional flags as nullable text) as text =>
let
f=if flags = null or flags ="" then "" else flags,
l1 = List.Transform({text, pattern, replace}, each Text.Replace(_, "\", "\\")),
l2 = List.Transform(l1, each Text.Replace(_, "'", "\'")),
t = Text.Format("<script>var txt='#{0}';document.write(txt.replace(new RegExp('#{1}','#{3}'),'#{2}'));</script>", List.Combine({l2,{f}})),
r=Web.Page(t)[Data]{0}[Children]{0}[Children],
Output=if List.Count(r)>1 then r{1}[Text]{0} else ""
in Output
in regexReplace
Válasz #2
Tudok JavaScriptet, de nem ismerem a Powerbit/Powerquery-t, szóval ez a válasz lehet, hogy hiányos.
Vannak más karakterek is, amelyeket escape-elni kell a karakterlánc literálokban.
Az egyszeres idézőjeles karakterlánc-literelek esetén a \ és a ' karaktereket el kell írni, akár néhány szóköz karaktert is, például újsor karaktert. Az elírások listája megtalálható a https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String oldalon. Néhány ezek közül opcionális, de nem vagyok biztos abban, pontosan melyek. Nem hiszem, hogy valaha is szükség lenne a hexadecimális számjegyekkel rendelkezőkre. Azt mondtam, hogy a ' karaktert el kell írni, de a "-ot nem, azonban ha dupla idézőjeles karakterláncot használtál volna ("#{0}"), ez fordítva lenne.
Ettől eltekintve nem tudom megmondani, milyen menekítést kell elvégezni a Powerquery számára. Valójában meglep, hogy a string literálod "\\" a várt módon működött.
Összefoglalva, valahogy így kellene kinéznie (és nyugodtan javítsd a Powerquery szintaxis hibáimat):
// Define function escapeString which inserts \ before each \ or ' and then applies the escape sequences \n, \r, \v, \t, \b and \f.
let
l = List.Transform({text, pattern}, each escapeString(_)),
...
