JavaScriptのRegExpで"g"オプションをつけた場合のtest()の挙動とベンチマーク

  • 投稿日:
  • by

JavaScriptのお話です。node.jsに限らない話だと思いますが、node.jsでの動作を説明します。

一言で言うと、"g"オプションをつけたRegExpのtest()の呼び出しはループ(?)します。

説明するよりも、実際の動きを見てみましょう。

% node
> re = new RegExp('xyz', 'g');
/xyz/g
> s = 'aaaxyzbbbxyz';
'aaaxyzbbbxyz'
> re.test(s)
true
> re.lastIndex
6
> re.test(s)
true
> re.lastIndex
12
> re.test(s)
false
> re.lastIndex
0
> re.test(s)
true
> re.lastIndex
6

という感じで、re.lastIndexがマッチを開始するインデックスを保持しているようです。で、最後まで行ったら初めに戻ると。

"g"オプションをつけなければこんなことにはならず、lastIndexも常に0のままです。


ついでに、RegExp.test()RegExp.exec()String.match()String.search()のベンチマークもしておきました。

一つは、node.js用。
https://gist.github.com/dai-shi/5169296

もう一つは、ブラウザ用。自分で作ろうかと思ったら、既にありました。
http://jsperf.com/regex-test-or-exec-or-string-search-or-match

やはり、正規表現のマッチを確認するだけなら、RegExp.test()が一番よさそうですね。

ちょっと面白い結果だったのはFirefoxのケースで、RegExp.test()RegExp.exec()の速さがほとんど変わりませんでした。つまり、test()の内部でexec()を呼び出しちゃってる感じです。Chromeとnode.jsでは(どちらもv8だけど)差が出ているので、FirefoxのJavaScriptエンジンは改善の余地があるということでしょう。

前から思っていましたが、Chromeの正規表現の処理は速いですねぇ。Firefoxとは比べものにならないです。