0. はじめに
Freeradicalの中の人、yamarahです。
Power Queryで正規表現を使いたいという要望は少なくないようで、検索すると国内外の記事がヒットします。例えば、Power Query で正規表現を使って置換したいなど。
しかし、これらの記事は、JavaScript, HTMLエンジンが反応する特殊文字をエスケープしていないので、入力によっては誤動作します。これを改良しようというのが、本記事の目的です。
私自身は、M言語, JavaScript, HTMLについては初心者なので、間違いや、もっと良い方法があれば、是非ご指摘願います。
1. エスケープすべき特殊文字
まずは、エスケープすべき特殊文字を確認しておきましょう。
JavaScript
スクリプト中の'
で囲われる文字列は、以下のようにエスケープする必要があります。
特殊文字 | エスケープ後 |
---|---|
\ | \\ |
' | \' |
HTML
JavaScriptの出力はHTMLエンジンによって解釈されてしまうので、タグ表記に用いる文字などをエスケープします。
後に出てくるコードを含めて、記事 : JavaScriptでHTMLエスケープ処理を参考にさせて頂きました。
特殊文字 | エスケープ後 |
---|---|
& | & |
' | ' |
` | ` |
" | " |
< | < |
> | > |
M言語
JavaScriptをM言語中に埋め込むにあたって、以下をエスケープして記述する必要があります。
特殊文字 | エスケープ後 |
---|---|
" | "" |
# | #(#) |
2. コード
入出力のインターフェースについては、各自調整されたし。
= (str as text, pattern as text, newSubStr as text) as nullable text =>
let
strEscaped = Text.Replace(
Text.Replace(str, "\", "\\"),
"'", "\'"),
patternEscaped = Text.Replace(
Text.Replace(pattern, "\", "\\"),
"'", "\'"),
newSubStrEscaped = Text.Replace(
Text.Replace(newSubStr, "\", "\\"),
"'", "\'"),
html =
"<script>
var str='"&strEscaped&"';
var pattern=new RegExp('"&patternEscaped&"','g');
var newSubStr='"&newSubStrEscaped&"';
var result=str.replace(pattern,newSubStr);
document.write(
result.replace(
/[&'`""<>]/g,
function (match) {
return {
'&': '&',
""'"": '&#(#)x27;',
'`': '&#(#)x60;',
'""': '"',
'<': '<',
'>': '>'
}[match]
}
)
);
</script>",
webPageResult = Web.Page(html)[Data]{0}[Children]{0}[Children],
result = if (List.Count(webPageResult) <= 1) then
{
null
} else if (webPageResult{1}[Text]{0} = null) then
{
"" as text
} else {
webPageResult{1}[Text]{0} as text
}
in
result{0}
注意点の1つ目は、JavaScript中で'
で括られる文字列のエスケープは2段階ありますが、この順番でやること(そうしないと'
をエスケープした\'
のバックスラッシュに反応してしまう)です。
2つ目は、JavaScript中の
'>': '>'
の後ろに,
を置かないことです。近代的なJavaScriptエンジンは最終行の後に,
を許容するようですが、PowerQueryが内部で使うエンジン(IE7相当?)ではエラーになります。