グローバルフラグ付きの RegExp.test が予想外の動きをする
正規表現が沢山あると、書くほうも読むほうもしんどいので、時々まとめちゃいます。
たとえば、こんなふうに。
function hoge(ary) { var i = 0, iz = ary.length, val; var rex = /\s*\!\s*important\s*/g; // グローバルフラグ付き for (; i < iz; ++i) { val = ary[i]; if (rex.test(val)) { // (2) ここでも流用 val = val.replace(rex, ""); // (1) ここ向けの正規表現を ... } else if (/!/.test(val)) { ... } } }
んで法則が発動したと
<!doctype html><html><head><title></title></head><body> <script> function test(route) { var ary = [ "background-color: pink !important", "color: red !important", "background-color: skyblue !important" ]; var rex = /\s*\!\s*important\s*/g; var rex2 = /\s*\!\s*important\s*/; var i = 0, iz = ary.length; var val; var result = []; for (; i < iz; ++i) { val = ary[i]; switch (route) { case 0: if (rex.test(val)) { // global val = val.replace(rex, ""); result.push(1); } else if (/!/.test(val)) { result.push(2); } else { result.push(3); } break; case 1: if (/\s*\!\s*important\s*/g.test(val)) { // global val = val.replace(rex, ""); result.push(1); } else if (/!/.test(val)) { result.push(2); } else { result.push(3); } break; case 2: if (/\s*\!\s*important\s*/.test(val)) { // not global val = val.replace(rex, ""); result.push(1); } else if (/!/.test(val)) { result.push(2); } else { result.push(3); } break; case 3: if (rex2.test(val)) { // not global val = val.replace(rex2, ""); // not global result.push(1); } else if (/!/.test(val)) { result.push(2); } else { result.push(3); } } } return result.join(" > "); } alert([test(0), test(1), test(2), test(3)].join("\n")); </script> </body></html>
ブラウザ毎の実行結果はこうなります。SafariとIE, OperaとFirefox が同じ結果になるのって非常に珍しい組み合わせですね。
Chrome | 1 > 2 > 1 |
1 > 2 > 1 | |
1 > 1 > 1 | |
1 > 1 > 1 | |
Safari | 1 > 2 > 1 |
1 > 1 > 1 | |
1 > 1 > 1 | |
1 > 1 > 1 | |
IE | 1 > 2 > 1 |
1 > 1 > 1 | |
1 > 1 > 1 | |
1 > 1 > 1 | |
Firefox | 1 > 1 > 1 |
1 > 2 > 1 | |
1 > 1 > 1 | |
1 > 1 > 1 | |
Opera | 1 > 1 > 1 |
1 > 2 > 1 | |
1 > 1 > 1 | |
1 > 1 > 1 |
/omatome/g.test(bugbug) は実装依存なので、使っちゃだめなんですね。
ECMAScript3 では、
15.10.6.3 RegExp.prototype.test(string)
式 RegExp.prototype.exec(string) != null と同様である。
とあるのですが、いったいどのブラウザの動きが正解なんでしょう? 良くわかりません。
そういえば、javascripter さんが…
http://d.hatena.ne.jp/javascripter/20090113/1231863436 で面白い使い方してたの思い出しました。
/omatome/g.test(hoge) の後に、 hoge.replace(/omatome/g, "") すると法則発動です。
/omatome/g.test(hoge) だけなら、lastIndex などに気をつければ大丈夫です。