グループと後方参照

グループは複数のパターンを全体としてグループ化し、グループをキャプチャすることで、正規表現パターンを使用して文字列と一致する場合に、追加の副一致情報を提供します。後方参照は、同じ正規表現で以前に捕捉したグループを参照します。

試してみましょう

種類

文字 意味
(x)

キャプチャグループ: x に一致し、一致した内容を記憶します。例えば /(foo)/ は "foo bar" の "foo" に一致し、記憶します。

正規表現は複数のキャプチャグループを持つことができます。結果、一般的にキャプチャグループ内の左括弧と同じ順にある、配列の要素のキャプチャグループに一致しています。たいていの場合、これはキャプチャグループ自身の順番です。これはキャプチャグループがネストしている場合に重要です。一致は結果の要素の添字 ([1], …, [n]) や、あらかじめ定義されている RegExp オブジェクトのプロパティ ($1, …, $9) を使ってアクセスできます。

キャプチャグループはパフォーマンス上の損失があります。一致した部分文字列を使わない場合はキャプチャなし括弧(後述)を使ったほうがいいでしょう。

String.prototype.match() は、/.../g フラグが設定されている場合、グループを返しません。しかし、 String.prototype.matchAll() を使用して、すべての一致したものを取得することができます。

(?<Name>x)

名前付きキャプチャグループ: "x" に一致し、<Name> で指定された名前に従い、返される一致の groups プロパティに記憶されます。山括弧 ('<' と '>') にはグループ名が必須です。

例えば、電話番号からアメリカのエリアコードを取り出す際、 /\((?<area>\d\d\d)\)/ を使うことができます。 結果の番号は matches.groups.area に表示されます。

(?:x)

キャプチャなしグループ: "x" に一致しますが、一致した内容は記憶しません。一致した部分文字列は、結果の配列の要素 ([1], …, [n]) や、あらかじめ定義されている RegExp オブジェクトのプロパティ ($1, …, $9) から呼び出すことはできません。

(?flags:x), (?:flags-flags:x)

修飾子: 指定したフラグを、囲まれたパターンに対してのみ有効または無効にします。修飾子では、ims フラグのみ使用できます。

\n

後方参照: "n" に正の整数が入ります。正規表現内において n 番目の括弧の部分に一致した最新の部分文字列への後方参照となります(括弧の数は左からカウントします)。例えば /apple(,)\sorange\1/ は "apple, orange, cherry, peach" の "apple, orange," に一致します。

\k<Name>

名前付き後方参照: <Name> で指定された名前付きキャプチャグループに一致する最後の部分文字列の後方参照です。

例えば、 /(?<title>\w+), yes \k<title>/ は、 "Do you copy? Sir, yes Sir!" の中の "Sir, yes Sir" に一致します。

メモ: \k は、ここでは、名前付きキャプチャグループの後方参照を開始することを示すために使用されています。

グループの使用

この例では、キャプチャグループを使用して記憶することにより、構造化された形式で 2 つの単語を照合します。 w+は 1 つ以上の単語文字と一致し、括弧 () はキャプチャグループを作成します。 g フラグはすべて一致させるために使用します。

js
const personList = `First_Name: John, Last_Name: Doe
First_Name: Jane, Last_Name: Smith`;

const regexpNames = /First_Name: (\w+), Last_Name: (\w+)/g;
for (const match of personList.matchAll(regexpNames)) {
  console.log(`Hello ${match[1]} ${match[2]}`);
}

それ以外の例は キャプチャグループリファレンスを参照してください。

名前付きグループの使用

この例も上と同じですが、代わりに名前付きキャプチャグループを使用して、一致した単語を記憶しています。この方法では、一致した単語をその意味によってアクセスすることができます。

js
const personList = `First_Name: John, Last_Name: Doe
First_Name: Jane, Last_Name: Smith`;

const regexpNames =
  /First_Name: (?<firstName>\w+), Last_Name: (?<lastName>\w+)/g;
for (const match of personList.matchAll(regexpNames)) {
  console.log(`Hello ${match.groups.firstName} ${match.groups.lastName}`);
}

それ以外の例は 名前付きキャプチャグループリファレンスを参照してください。

グループと後方参照の使用

この例では、最初に単一の引用符または二重引用符を ['"] で照合し、それを記憶し、任意の数の文字を .*? (*?貪欲ではない数量子)で任意の数の文字と照合し、˶1 で再び記憶された引用符文字と照合します。 \1 は最初のキャプチャグループへの後方参照で、同じ型の引用符に照合します。したがって、結果は "'"'"' の 2 つの文字列になります。

js
const quote = `単一引用符 "'" と二重引用符 '"'`;
const regexpQuotes = /(['"]).*?\1/g;
for (const match of quote.matchAll(regexpQuotes)) {
  console.log(match[0]);
}

それ以外の例は 後方参照リファレンスを参照してください。

グループと一致結果の添字の使用

d フラグが指定された場合、各キャプチャグループの添字を返します。これは、それぞれの一致したグループと元のテキストを関連付ける場合、例えば、コンパイラーの診断を提供する場合に特に有益です。

js
const code = `function add(x, y) {
  return x + y;
}`;
const functionRegexp =
  /(function\s+)(?<name>[$_\p{ID_Start}][$\u200c\u200d\p{ID_Continue}]*)/du;
const match = functionRegexp.exec(code);
const lines = code.split("\n");
lines.splice(
  1,
  0,
  " ".repeat(match.indices[1][1] - match.indices[1][0]) +
    "^".repeat(match.indices.groups.name[1] - match.indices.groups.name[0]),
);
console.log(lines.join("\n"));
// function add(x, y) {
//          ^^^
//   return x + y;
// }

関連情報