JavaScript 正規表現 ルックアラウンド

JavaScript正規表現のルックアラウンドとは

JavaScript の正規表現において「ルックアラウンド」と呼ばれているパターンマッチングには大きく分けて二種類あります。 ひとつは「ルックアヘッド」で、もうひとつは「ルックビハインド」です。

さらに、「ルックアヘッド」と「ルックビハインド」のそれぞれに、「ポジティブ」(マッチの場合) と「ネガティブ」(マッチしない場合) があります。

「ルックアラウンド」を使うと、パターン前後に特定の文字がある場合にマッチ、あるいはマッチしないという条件を記述することができます。

(?=a) JavaScript正規表現 ポジティブルックアヘッド

(?=a)はポジティブルックアヘッドであり、「次に a があればマッチする」という意味になります。

次の例では数値の部分が全てマッチしています。

const s = 'iPhone 12 15% OFF'
for (let m of s.matchAll(/\d+/g)) {
  console.log(m[0])
}
// 12
// 15

ポジティブルックアヘッド (?=) を用いることで、パーセントの数値である箇所だけがマッチしています。

const s = 'iPhone 12 15% OFF'
for (let m of s.matchAll(/\d+(?=%)/g)) {
  console.log(m[0])
}
// 15

単純に % をパターンに含めた場合は、 %も含めてマッチします。

const s = 'iPhone 12 15% OFF'
for (let m of s.matchAll(/\d+%/g)) {
  console.log(m[0])
}
// 15%

(?!a) JavaScript正規表現 ネガティブルックアヘッド

(?!a)はネガティブルックアヘッドであり、「次にaがあればマッチしない」という意味になります。

ネガティブルックアヘッドを用いる具体例として、航空機の便名を考えてみましょう。

便名は「英数字の2桁からなる航空会社コード」と「数字4桁以内からなるフライト番号」で構成されます。 例えば NH1051U97 などは正しい便名です。

これを考慮すると、便名にマッチするパターンは、英数字2桁と数字4桁以内のパターンとして [A-Z0-9]{2}\d{1,4} と書けます。

ところがもうひとつ条件があり、航空会社コードとしては数字のみ2桁はありません。つまり、はじめの2桁がともに数字である 12345 は正しい便名ではありません。

以上を配慮すると、便名にマッチするパターンは次のように書けます。

const r = /^(?!\d{2})[A-Z0-9]{2}\d{1,4}$/
console.log(r.test('NH105')) // true
console.log(r.test('1U97')) // true
console.log(r.test('12345')) // false

ネガティブルックアヘッドを利用することで、数字2桁となる航空会社コードをマッチする条件から除外しています。

(?<=a) JavaScript正規表現ポジティブルックビハインド

(?<=a)はポジティブルックビハインドであり、「前に a があればマッチする」という意味になります。

次の例では数値の部分が全てマッチしています。

const s = 'iPhone 12 for $699'
for (let m of s.matchAll(/\d+/g)) {
  console.log(m[0])
}
// 12
// 699

次の例ではポジティブルックビハインド (?<=) を用いることで、アメリカドル表記の数値の箇所だけがマッチしています。

const s = 'iPhone 12 for $699'
for (let m of s.matchAll(/(?<=\$)\d+/g)) {
  console.log(m[0])
}
// 699

(?<!a) JavaScript正規表現ネガティブルックビハインド

(?<!a)はネガティブルックビハインドであり、「前に aがあればマッチしない」という意味になります。

次の例では数値の部分が全てマッチしています。

const s = 'iPhone 12 for $699'
for (let m of s.matchAll(/\b\d+\b/g)) {
  console.log(m[0])
}
// 12
// 699

次の例ではネガティブルックビハインド (?<!)を用いることで、アメリカドル表記の数値の箇所はマッチしていません。

const s = 'iPhone 12 for $699'
for (let m of s.matchAll(/\b(?<!\$)\d+\b/g)) {
  console.log(m[0])
}
// 12

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 JavaScript 入門