🍣
Javascriptの正規表現 グローバルフラグでtestの結果が変わる話
Javascriptの正規表現のグローバルフラグ g によって、正規表現のtestを複数回実行した場合に予期しない結果を返すことがあります。
事例
バージョン番号が正しいかをチェックする正規表現を例に説明します。
次のコードのように文字列がバージョン番号であるかどうかを示す正規表現を作成して、test で文字列が正規表現にマッチングするかチェックします。
このときに、test を複数回呼び出すと true となるはずの結果が false となることがあります。
const versionPatternG = /^\d+\.\d+\.\d+\.\d+$/g;
versionPatternG.test('2.0.6.121'); // => true
versionPatternG.test('2.0.6.122'); // => false
原因は /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/g の グローバルフラグ g が原因でした。
今回のケースでは g は使用する必要がなかったので取り除いて実行したところ、想定通りの結果を返しました。
const versionPattern = /^\d+\.\d+\.\d+\.\d+$/;
versionPattern.test('2.0.6.121'); // => true
versionPattern.test('2.0.6.122'); // => true
グローバルフラグを持つ正規表現の test() の使用
グローバルフラグ g を付けることで正規表現が持つ lastIndex が加算されることが原因でした。
lastIndex が加算されて、次に指定した文字列でも lastIndex の位置から探索を行うため、test で想定しているマッチングができなくなりました。
そして、test の結果が false になると、lastIndex が 0 にリセットされます。
正規表現にグローバルフラグが設定されている場合、 test() は正規表現が所有する lastIndex の値を加算します。 (exec() も同様に lastIndex プロパティの値を加算します。)
Discussion