Prompt
正規表現の後方参照とは?
後方参照(backreference)とは、正規表現において、以前にキャプチャグループでマッチした文字列を再利用する機能だよ。これは、特定のパターンが繰り返されたり、同じ文字列が複数回出現したりするパターンを表現するのに使われるんだ。
後方参照の仕組み
正規表現で括弧 () を使うと、その括弧内のパターンにマッチした文字列がキャプチャグループとして記憶される。後方参照は、この記憶された文字列を参照するために、\1 や \2 のような番号付きの記号を使うんだ。
-
\1: 1番目のキャプチャグループにマッチした文字列を参照する。 -
\2: 2番目のキャプチャグループにマッチした文字列を参照する。
キャプチャグループの番号は、正規表現の左から数えて、開き括弧 ( が現れる順番で決まるよ。
JavaScript
// "abcabc" や "xyzxyz" のように、同じ文字列が2回繰り返されるパターンにマッチ
const regex = /(abc|xyz)\1/;
console.log(regex.test('abcabc')); // true
console.log(regex.test('xyzxyz')); // true
console.log(regex.test('abcxyz')); // false
この例では、\1が/(abc|xyz)/という1番目のキャプチャグループの内容を参照しているよ。
後方参照の主な使い道
1. 繰り返しのパターンにマッチさせる
文字列の中で同じパターンが連続して出現する場合に、そのパターンを正確に特定するために使う。
JavaScript
// "hogehoge" や "foobarfoobar" のように、単語が2回繰り返されるパターンにマッチ
const regex = /(\w+)\1/;
console.log(regex.test('hogehoge')); // true
console.log(regex.test('foobarfoobar')); // true
console.log(regex.test('foobarbarfoo')); // false
\w+は1つ以上の単語構成文字にマッチし、\1でそのマッチした内容が繰り返されているかをチェックする。
2. HTMLタグの閉じタグを検証する
HTMLの開始タグと閉じタグがペアになっているかを簡易的にチェックする場合に、後方参照が役立つよ。
JavaScript
// <b>...</b> や <i>...</i> のように、開始タグと閉じタグのペアにマッチ
// ただし、この方法はHTMLの完全なパースには不向き
const regex = /<(\w+)>.*<\/\1>/;
console.log(regex.test('<b>hello</b>')); // true
console.log(regex.test('<b>hello</i>')); // false
console.log(regex.test('<div><span>text</span></div>')); // true
(\w+)で開始タグの名前(例: bやdiv)をキャプチャし、\1で閉じタグの\bと\w+にマッチした文字列が同じであることを検証している。
3. 文字列の置換(String.prototype.replace())
後方参照は、正規表現でマッチした文字列を新しい文字列に組み込む際にも非常に便利だよ。
JavaScript
const str = "hello world";
const regex = /(\w+)\s(\w+)/;
// `$1`と`$2`でキャプチャグループの内容を参照して、単語の順番を入れ替える
const replacedStr = str.replace(regex, '$2 $1');
console.log(replacedStr); // "world hello"
String.prototype.replace()では、後方参照を$1, $2のように$プレフィックスで指定するのが一般的だ。
名前付き後方参照
多くのモダンな正規表現エンジンでは、番号ではなく名前を付けて後方参照を行うこともできる。これにより、可読性が向上するよ。
(?<name>...) という構文でグループに名前を付け、\k<name> という構文で参照する。
JavaScript
// JavaScript (ES2018以降) での名前付きキャプチャグループ
const regex = /(?<word>\w+)\s\k<word>/;
console.log(regex.test('test test')); // true
console.log(regex.test('test foo')); // false
後方参照を理解することで、より複雑で柔軟なパターンマッチングを、正規表現で簡潔に表現できるようになるよ。