2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Power Queryでの正規表現置換で、特殊文字に対応する

Posted at

0. はじめに

Freeradicalの中の人、yamarahです。
Power Queryで正規表現を使いたいという要望は少なくないようで、検索すると国内外の記事がヒットします。例えば、Power Query で正規表現を使って置換したいなど。
しかし、これらの記事は、JavaScript, HTMLエンジンが反応する特殊文字をエスケープしていないので、入力によっては誤動作します。これを改良しようというのが、本記事の目的です。
私自身は、M言語, JavaScript, HTMLについては初心者なので、間違いや、もっと良い方法があれば、是非ご指摘願います。

1. エスケープすべき特殊文字

まずは、エスケープすべき特殊文字を確認しておきましょう。

JavaScript

スクリプト中の'で囲われる文字列は、以下のようにエスケープする必要があります。

特殊文字 エスケープ後
\ \\
' \'

HTML

JavaScriptの出力はHTMLエンジンによって解釈されてしまうので、タグ表記に用いる文字などをエスケープします。
後に出てくるコードを含めて、記事 : JavaScriptでHTMLエスケープ処理を参考にさせて頂きました。

特殊文字 エスケープ後
& &
' '
` `
" "
< &lt;
> &gt;

M言語

JavaScriptをM言語中に埋め込むにあたって、以下をエスケープして記述する必要があります。

特殊文字 エスケープ後
" ""
# #(#)

2. コード

入出力のインターフェースについては、各自調整されたし。

RegExReplace
= (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 {
                    '&': '&amp;',
                    ""'"": '&#(#)x27;',
                    '`': '&#(#)x60;',
                    '""': '&quot;',
                    '<': '&lt;',
                    '>': '&gt;'
                  }[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中の

'>': '&gt;'

の後ろに,を置かないことです。近代的なJavaScriptエンジンは最終行の後に,を許容するようですが、PowerQueryが内部で使うエンジン(IE7相当?)ではエラーになります。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?