CakeFest 2024: The Official CakePHP Conference

後方参照

文字クラス外で、バックスラッシュに続いて 1 以上の数値(複数桁可) を記述したものは、パターン中のより前方(すなわち左)にある キャプチャ用サブパターンに対する後方参照 (back reference) です。ただし、 その左方に、その数値以上の個数のキャプチャ用サブパターンの開きカッコが ある必要があります。

なお、バックスラッシュの後に 10 未満の 10 進数が続く場合は 常に後方参照として解釈され、パターン全体で指定した個数以上の キャプチャ用サブパターンが無いとエラーが発生します。言いかえると、 参照されるカッコは、10未満の番号に対しては、参照する側の左にある必要がないということです。 "前方にある後方参照 (forward back reference)" が意味をなすのは、 繰り返しが含まれていて、右側へのサブパターンがその前の反復に含まれている場合です。 バックスラッシュの後に数字が続く場合の処理の詳細については、 エスケープシーケンス のセクションを参照ください。

後方参照は、カレントの対象文字列においてキャプチャ用サブパターンが 実際にマッチした文字列にマッチします。サブパターンがパターンとして マッチし得るものではありません。すなわち、パターン

      (sens|respons)e and \1ibility
      
は、"sense and sensibility" および "response and responsibility" にマッチしますが、 "sense and responsibility" にはマッチしません。また、 後方参照が記述されている位置で大小文字を区別するマッチングが有効ならば、 文字の大小文字の別も関係します。例えば、
      ((?i)rah)\s+\1
      
は、"rah rah" および "RAH RAH" にマッチしますが、 元のキャプチャ用サブパターンは大小文字を区別しないマッチングを 行っているにもかかわらず、"RAH rah" にはマッチしません

同じサブパターンに対して、複数回の後方参照を行うことができます。 また、使われなかったサブパターンに対する後方参照を行おうとすると、 マッチが失敗します。例えば、パターン

      (a|(bc))\2
      
は、はじめに "bc" でなく "a" にマッチした場合は、マッチが失敗します。 最大 99 番までの後方参照を使用できるため、バックスラッシュの後に 数字が続くものはすべて後方参照番号の可能性があるものとして解釈されます。 後に数字が続く場合、後方参照を終了するためになんらかの区切り文字を 置く必要があります。PCRE_EXTENDED オプションを設定している場合は空白文字を区切り文字として使えます。 その他の場合は空のコメントを使います。

後方参照を、それ自身が参照するサブパターンのカッコ内に記述した場合、 そのサブパターンが最初に使われた際にマッチが失敗します。ですので、 (a\1) は、何にもマッチしません。しかし、このような参照は、 複数回繰り返されるサブパターンの内部では有用です。例えば、パターン

      (a|b\1)+
      
は、"a" が連続するものや "aba", "ababba" 等にマッチします。 サブパターンが繰り返される場合、後方参照は、直前の繰り返しで一致した 文字列にマッチします。こうしたパターンを動作させるためには、 繰り返しの1 回目に、後方参照を含むパターンとのマッチングが 行われないことが必要です。これには、上の例のように選択肢を使うか、 下限が 0 回の量指定子を使います。

エスケープシーケンス \g を使ってサブパターンの絶対参照および相対参照を行うことができます。 このエスケープシーケンスの後には符号なしの数値あるいは負の数値を続けなければなりません。 数値は波括弧で囲むこともできます。\1\g1 および \g{1} は、 すべて同じ意味になります。符号なし数値でこの方式を使えば、 バックスラッシュの後に数値を続ける方式がもつあいまいさを排除できます。 この方式を使えば後方参照と八進数値を明確に区別することができ、 さらに、後方参照のあとに数値リテラルが続く \g{2}1 のようなパターンも書きやすくなります。

\g シーケンスで負の数値を使うと、 それは相対参照を表します。たとえば (foo)(bar)\g{-1} は "foobarbar" にマッチし、(foo)(bar)\g{-2} は "foobarfoo" にマッチします。 これは、長いパターンの中で特定のサブパターンを参照する場合に便利です。 それが何番目のサブパターンになるかをいちいち覚えておくかわりに、 相対指定することができるからです。

名前を指定したサブパターンへの後方参照を行うには (?P=name) とします。 これ以外にも \k<name>, \k'name', \k{name}, \g{name}, \g<name>, \g'name' の形も使えます。

add a note

User Contributed Notes 2 notes

up
13
mnvx at yandex dot ru
7 years ago
Something similar opportunity is DEFINE.

Example:
(?(DEFINE)(?<myname>\bvery\b))(?&myname)\p{Pd}(?&myname).

Expression above will match "very-very" from next sentence:
Define is very-very handy sometimes.
^-------^

How it works. (?(DEFINE)(?<myname>\bvery\b)) - this block defines "myname" equal to "\bvery\b". So, this block "(?&myname)\p{Pd}(?&myname)" equvivalent to "\bvery\b\p{Pd}\bvery\b".
up
0
Steve
1 year ago
The escape sequence \g used as a backreference may not always behave as expected.
The following numbered backreferences refer to the text matching the specified capture group, as documented:
\1
\g1
\g{1}
\g-1
\g{-1}

However, the following variants refer to the subpattern code instead of the matched text:
\g<1>
\g'1'
\g<-1>
\g'-1'

With named backreferences, we may also use the \k escape sequence as well as the (?P=...) construct. The following combinations also refer to the text matching the named capture group, as documented:
\g{name}
\k{name}
\k<name>
\k'name'
(?P=name)

However, these refer to the subpattern code instead of the matched text:
g<name>
\g'name'

In the following example, the capture group searches for a single letter 'a' or 'b', and then the backreference looks for the same letter. Thus, the patterns are expected to match 'aa' and 'bb', but not 'ab' nor 'ba'.

<?php
/* Matches to the following patterns are replaced by 'xx' in the subject string 'aa ab ba bb'. */
$patterns = [
# numbered backreferences (absolute)
'/([ab])\1/', // 'xx ab ba xx'
'/([ab])\g1/', // 'xx ab ba xx'
'/([ab])\g{1}/', // 'xx ab ba xx'
'/([ab])\g<1>/', // 'xx xx xx xx' # unexpected behavior, backreference matches both 'a' and 'b'.
"/([ab])\g'1'/", // 'xx xx xx xx' # unexpected behavior, backreference matches both 'a' and 'b'.
'/([ab])\k{1}/', // 'aa ab ba bb' # No group with name "1", backreference to unset group always fails.
'/([ab])\k<1>/', // 'aa ab ba bb' # No group with name "1", backreference to unset group always fails.
"/([ab])\k'1'/", // 'aa ab ba bb' # No group with name "1", backreference to unset group always fails.
'/([ab])(?P=1)/', // NULL # Regex error: "subpattern name must start with a non-digit", (?P=) expects name not number.
# numbered backreferences (relative)
'/([ab])\-1/', // 'aa ab ba bb'
'/([ab])\g-1/', // 'xx ab ba xx'
'/([ab])\g{-1}/', // 'xx ab ba xx'
'/([ab])\g<-1>/', // 'xx xx xx xx' # unexpected behavior, backreference matches both 'a' and 'b'.
"/([ab])\g'-1'/", // 'xx xx xx xx' # unexpected behavior, backreference matches both 'a' and 'b'.
'/([ab])\k{-1}/', // 'aa ab ba bb' # No group with name "-1", backreference to unset group always fails.
'/([ab])\k<-1>/', // 'aa ab ba bb' # No group with name "-1", backreference to unset group always fails.
"/([ab])\k'-1'/", // 'aa ab ba bb' # No group with name "-1", backreference to unset group always fails.
'/([ab])(?P=-1)/', // NULL # Regex error: "subpattern name expected", (?P=) expects name not number.
# named backreferences
'/(?<name>[ab])\g{name}/', // 'xx ab ba xx'
'/(?<name>[ab])\g<name>/', // 'xx xx xx xx' # unexpected behavior, backreference matches both 'a' and 'b'.
"/(?<name>[ab])\g'name'/", // 'xx xx xx xx' # unexpected behavior, backreference matches both 'a' and 'b'.
'/(?<name>[ab])\k{name}/', // 'xx ab ba xx'
'/(?<name>[ab])\k<name>/', // 'xx ab ba xx'
"/(?<name>[ab])\k'name'/", // 'xx ab ba xx'
'/(?<name>[ab])(?P=name)/', // 'xx ab ba xx'
];

foreach (
$patterns as $pat)
echo
" '$pat',\t// " . var_export(@preg_replace($pat, 'xx', 'aa ab ba bb'), 1) . PHP_EOL;
?>
To Top