正規表現とループでハマりどころ
gist: 807644 - GitHubを書いててハマってたのでメモ。
既に正規表現リテラルで作った正規表現オブジェクトをループ内で回すと、ES3では正規表現オブジェクトが再利用されちゃって、lastIndexが毎回0になってくれないためおかしな動作になるという事は知っていた(2回に1回正しくなってるみたいな感じになる)
ただし、ES5だとリテラルもその都度オブジェクトを作るようになるので問題なくなる。
これの解決方法としてループ内で毎回new RegExpするのはコスト的にあんまり良くない気がしたので、頑なにtestメソッドを使うなら毎回re.lastIndex=0とすると大丈夫になる。
String.prototype.search (regexp)の返り値はindexOfのようにオフセットの数値が返ってくるので、マッチしなかったときは-1となる。
jsのオレオレ演算子 - latest logみたいなやつで、!!~数値 で-1の時はfalse,他はtrueになるのでそれを使った。(あってる?)
2回に一回できるという点でこれを思い出した。
と、ここまで書いたところで、元スクリプトの正規表現にはgオプションがいらない気がした…
既に正規表現リテラルで作った正規表現オブジェクトをループ内で回すと、ES3では正規表現オブジェクトが再利用されちゃって、lastIndexが毎回0になってくれないためおかしな動作になるという事は知っていた(2回に1回正しくなってるみたいな感じになる)
ただし、ES5だとリテラルもその都度オブジェクトを作るようになるので問題なくなる。
for (var k = 0; k < 4; k++) {
var re = /ec/g;
alert(re.lastIndex); // 0, 2, 0, 2
alert(re.test("ecmascript")); // true, false, true, false
}
// こちらは毎回ループ内でnewして違うオブジェクトになるのでOK
for (var k = 0; k < 4; k++) {
var re = new RegExp("ec", "g");
alert(re.lastIndex); // 0,0,0, 0
alert(re.test("ecmascript")); // true, true, true, true
}
で、上のを知っていたんだけど、なぜかリテラルの場合はループでおかしくなるという変な理解になっていて、実際にはnew RegExpでも、ループの外で一回だけ正規表現オブジェクトを作ってそれを継続して利用する場合もおかしくなる。
var re1 = /ec/g;
var re2 = new RegExp("ec", "g");
for (var k = 0; k < 4; k++) {
console.group("re1-"+k)
console.log(re1.lastIndex); // 0, 2, 0, 2
console.log(re1.test("ecmascript")); // true, false, true, false
console.groupEnd("re1-"+k);
}
for (var k = 0; k < 4; k++) {
console.group("re2-"+k)
console.log(re2.lastIndex); // 0, 2, 0, 2
console.log(re2.test("ecmascript")); // true, false, true, false
console.groupEnd("re2-"+k);
}
普通に考えると当たり前ですね。これの解決方法としてループ内で毎回new RegExpするのはコスト的にあんまり良くない気がしたので、頑なにtestメソッドを使うなら毎回re.lastIndex=0とすると大丈夫になる。
var re = new RegExp("ec", "g");
for (var k = 0; k < 4; k++) {
console.group("re-"+k)
re.lastIndex = 0;// ここで0にする
console.log(re.lastIndex); // 0, 0, 0, 0
console.log(re.test("ecmascript")); // true, true, true, true
console.groupEnd("re-"+k);
}
ただ、re.lastIndex = 0;と毎回入れるのは見栄えがあんまり良くない気がしたので、searchメソッドを使えば自動的にやってくれるそうなのでそれを使うようにした。
String.prototype.searchが! lastIndex = 0かわりにやってくれますよ.
Twitter / utatane: @azu_re String.prototype.s ...
String.prototype.search (regexp)の返り値はindexOfのようにオフセットの数値が返ってくるので、マッチしなかったときは-1となる。
jsのオレオレ演算子 - latest logみたいなやつで、!!~数値 で-1の時はfalse,他はtrueになるのでそれを使った。(あってる?)
var re = new RegExp("ec", "g");
for (var k = 0; k < 4; k++) {
console.group("re-"+k)
console.log(re.lastIndex); // 0, 0, 0, 0
console.log(!!~"ecmascript".search(re)); // true, true, true, true
console.groupEnd("re-"+k);
}
というわけで、正規表現にgオプション付けてforループなどの時は何となく気を遣うようにしましょう。2回に一回できるという点でこれを思い出した。
と、ここまで書いたところで、元スクリプトの正規表現にはgオプションがいらない気がした…
コメント(0件)
- TB-URL http://efcl.info/adiary/094/tb/