正規表現のeオプションをJavaScriptでエミュレート

Perlなどの置換系の正規表現ではeというオプション(フラグ)をつけると、置換後の文字列をプログラム・コードとみなしてくれるわけですが、JavaScriptのreplace()の第一引数で指定する正規表現にはeオプションなどというモノはありません。しかし、replace()の第二引数である置換後の文字列にはStringオブジェクトや文字列リテラル以外にも関数を指定することもできるので、事実上eオプション相当のことが実現できます。エミュレートというのは正確ではない気がするけど気にしない。

具体的には、

var s = "asdf123asdf123456asdf123asdf";
document.write(
  s.replace(
    /123/g,
    function (num, idx, old) {
      return parseInt(num) + 333;
    }
  )
);

という感じ。上記例では「asdf456asdf456456asdf456asdf」と書き出されます。

第二引数に指定した関数には、強制的に引数が渡されます。その引数はreplace()によって随時変更されるグローバルなRegExpオブジェクトのプロパティの一部で、「RegExp.lastMatch, RegExp.$1..RegExp.$9, RegExp.index, RegExp.input」となっています(引数の数は正規表現に依存)。上記例では

123, 4, asdf123asdf123456asdf123asdf
123, 11, asdf123asdf123456asdf123asdf
123, 21, asdf123asdf123456asdf123asdf

などと渡されることになります(上記例の正規表現では()によるグルーピングはしていないのでRegExp.$1..RegExp.$9は飛ばされます)。

ちなみに、僕は知らなかったのですが、JavaScriptでpreg_replace_callbackというエントリが某所で話題になった時、「無いことは無いだろー」とWSH 5.6のヘルプのreplace()のページを読んでみたところ、そのものずばりな答えが載ってたりしました。知られざる常識・・・じゃなくてめちゃくちゃ常識だったりして。

JavaScriptのreplace()ではベタな正規表現による置換くらいしかやったことが無かったので、これを使えばエレガントなコードを書けるような気がしないでもない。