2008-05-05

RegExp.prototype.testのインデックスバグ?

JSON変換の独自実装を作成したのでテストをしようと思い、他人のライブラリの結果とマッチングしてテストを行ったのですが、特定の文字がアンマッチしてしまい原因を調べたところ標題の事象を発見しました。

内容としては全ての文字で「true」と表示される次のコードを実行したところ、replaceメソッドは問題ないのですがtestメソッドがFirefoxとOpera、Rhinoでtrueとfalseを交互に出力してしまいました。
var r = "";
for(var i=0; i<256; i++){
var s = String.fromCharCode(i);
r += i.toString(16) + ":";
r += /[\x00-\xff]/g.test(s) + ":" ;
r += s.replace(/[\x00-\xff]/g,"aiueo").length + "\n";
}
alert(r);

また、直書きしているRegExpオブジェクトを変数に入れて実行したところ、FirefoxとOperaは全てtrueとなりましたが、今度はSafariがtrueとfalseを繰り返し、IEでは一つ目がtrue、二つ目以降はfalseと表示されてしまいました。

試行錯誤したところ、testメソッドを呼ぶRegExpオブジェクトをnew演算子でインスタンス化すると問題なく動作するようになりました。
var r = "";
for(var i=0; i<256; i++){
var s = String.fromCharCode(i);
r += i.toString(16) + ":";
r += new RegExp("[\\x00-\\xff]","g").test(s) + ":" ;
r += s.replace(/[\x00-\xff]/g,"aiueo").length + "\n";
}
alert(r);


原因ははっきりとわからないのですが、IEに限っては直書きすると内部で変なキャッシュが効いてしまいインデックスを共有化してしまうのではないかと思っています(IE4で同じようなバグがありますし)。他のブラウザについても似たようなものなのかなと思っています。
原因がわからないのは気持ち悪いですがtestメソッドをクロスブラウザで使う場合はその都度、new演算子でインスタンス化して呼び出す必要があるようです。ちなみにnew演算子で作成したものを変数にいれて使いまわしてもtrueとfalseが交互に表示されます。

0 件のコメント: