🍣
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