あなたが観察している現象は、Perl とは異なり、PCRE サブパターンの再帰が原子的であるという事実によるものです。man ページには、実際にこの問題が非常に詳細に記載されています。
PCRE では (Python に似ていますが、Perl とは異なります)、再帰的なサブパターン呼び出しは
常にアトミック グループ として扱われます。つまり、サブジェクト文字列の一部と一致すると、未試行の代替が含まれていて、その後の一致の失敗があったとしても、再入力されることはありません。
これは、奇数個の文字 (たとえば、、、、) を含む回文文字列に一致すると主張する次のパターンで説明
"a"
でき"aba"
ます。"abcba"
"abcdcba"
^(.|(.)(?1)\2)$
これは、単一の文字、またはサブパリンドロームを囲む 2 つの同一の文字のいずれかに一致するという考え方です。Perl では、このパターンが機能します。PCRE では、パターンが 3 文字より長い場合はそうではありません。
件名の文字列を考えてみましょう"abcba"
:
最上位では、最初の文字が一致しますが、文字列の最後ではないため、最初の代替は失敗します。サブパターン 1 への再帰呼び出しは、次の文字 ( "b"
) と正常に一致します。(行頭テストと行末テストは再帰の一部ではないことに注意してください)。
最上位レベルに戻ると、次の文字 ( "c"
) が、サブパターン 2 が一致したもの ( ) と比較され"a"
ます。これは失敗します。再帰はアトミック グループとして扱われるため、バックトラッキング ポイントがなくなり、一致全体が失敗します。(この時点で、Perl は再帰を再入力して 2 番目の選択肢を試すことができます。) しかし、パターンが別の順序で選択肢とともに書かれている場合、状況は異なります:
^((.)(?1)\2|.)$
今回は、再帰の代替案が最初に試行され、再帰が失敗する時点で文字がなくなるまで再帰を続けます。しかし今回は、より高いレベルで試す別の選択肢があります。それが大きな違いです。前のケースでは、残りの代替手段はより深い再帰レベルにあり、PCRE では使用できません。
文字数が奇数の文字列だけでなく、すべての回文文字列に一致するようにパターンを変更するには、パターンを次のように変更したくなるでしょう。
^((.)(?1)\2|.?)$
繰り返しますが、これは Perl では機能しますが、PCRE では機能しません。同じ理由で. より深い再帰が単一の文字に一致した場合、空の文字列に一致するために再度入力することはできません。解決策は、2 つのケースを分離し、奇数と偶数のケースを上位レベルの代替案として書き出すことです。
^(?:((.)(?1)\2|)|((.)(?3)\4|.))$
警告!!!
上記の回文マッチング パターンは、対象文字列が文字列全体よりも短い回文で始まっていない場合にのみ機能します。たとえば、"abcba"
は正しく一致しますが、件名が の場合"ababa"
、PCRE は"aba"
最初に回文を見つけ、文字列の最後が続いていないため、最上位で失敗します。繰り返しになりますが、再帰に戻って他の選択肢を試すことはできないため、一致全体が失敗します。
その他の参考資料
パターンを詳しく見る
原子性の議論は正しいですが、パターンが観察されたように振る舞う理由をどのように説明するかはおそらく明らかではありません。詳しく見て、これがどのように適合するかを見てみましょう。
最初のパターンを使用します。
^(([a-z])(?1)\2|[a-z]?)$
再帰を表すために次の表記を使用します。
1
キャラクターが最初の代替でグループ 2 にキャプチャされたことを意味します
2
文字が 2 番目の代替文字と一致したことを意味します
- または、
2
が文字の上にない場合、 のゼロ繰り返しオプション?
が実行されます
\
文字が最初の代替でグループ 2 への後方参照によって一致したことを意味します
_
再帰的な枝の底を示します
- 他の選択肢があっても、この分岐は再入力されません!
"aaa"
次に、入力として考えてみましょう。
_
1 1 1 2
a a a # This is the first bottom of the recursion,
# now we go back to the third 1 and try to match \.
# This fails, so the third 1 becomes 2.
_
1 1 2
a a a # Now we go back to the second 1 and try to match \.
# This fails, so the second 1 becomes 2.
_
1 2
a a a # The second level matched! now we go back to the first level...
_____
1 2 \
a a a # Now the first 1 can match \, and entire pattern matches!!
今考えてみましょう"aaaaa"
:
_
1 1 1 1 1 2
a a a a a # Fifth 1 can't match \, so it becomes 2.
_
1 1 1 1 2
a a a a a # Fourth 1 can't match \, so it becomes 2.
_____
1 1 1 2 /
a a a a a # Here's a crucial point. The third 1 successfully matched.
# Now we're back to the second 1 and try to match \, but this fails.
# However, since PCRE recursion is atomic, the third 1 will NOT be
# reentered to try 2. Instead, we try 2 on the second 1.
_____
1 2 \
a a a a a # Anchors don't match, so the first 1 becomes 2, and then also the
# anchors don't match, so the pattern fails to match.
PCRE サブパターンの再帰はアトミックであるため、最初の選択肢で再帰レベルが一致すると、2 番目の選択肢は将来 (たとえそうすることが一致する可能性があるとしても) 試行されないことに注意してください。
今考えてみましょう"aa"
:
_
1 1 2
a a
_
1 2
a a # The second level matched by taking the one repetition option on ?.
# We now go back to the first level, and we can't match \.
# Since PCRE recursion is atomic, we can't go back to the second level
# to try the zero repetition option on ?.
_
2
a a # Anchors don't match, trying zero option on ? also doesn't help,
# so the pattern fails to match!
PCRE サブパターンの再帰はアトミックであるため、再帰レベル?
が 2 番目の選択肢の 1 回の繰り返しで一致すると、ゼロ繰り返しオプションは将来試行されないことに注意してください。
では、考えてみましょうaaaaaaa
_
1 1 1 1 1 1 1 2
a a a a a a a
_
1 1 1 1 1 1 2
a a a a a a a
_____
1 1 1 1 1 2 \
a a a a a a a # A crucial point: the fifth level matched and now the fourth
# level can't match \, but it does NOT reenter the fifth level to
# try 2. Instead, the fourth level tries 2.
_____
1 1 1 2 \
a a a a a a a
_________
1 1 1 2 \ \
a a a a a a a
_____________
1 1 1 2 \ \ \
a a a a a a a # Entire pattern is a match!
PCRE サブパターンの再帰はアトミックですが、2 n -1 回繰り返される文字で構成される回文にうまく一致することに注意してください。
さて、楽しみのために、試してみましょう"abcba"
:
_
1 1 1 1 1 2
a b c b a
_
1 1 1 1 2
a b c b a
1 1 1 2
a b c b a # Third level attempts \, but c does not match a!
# So we go back to third 1 and try 2.
_____
1 1 2 \
a b c b a
_________
1 1 2 \ \
a b c b a # Entire pattern is a match!
つまり、パターンは「文字が 2 n -1 回繰り返される場合にのみ」一致するだけではありません。実際に一致する可能性があります"abcba"
( ideone.com で見られるように)。ただし、 PCRE のサブパターン再帰はアトミックであるため、 と一致することも、一致"ababa"
することもありません"aaaaa"
(man ページの WARNING を参照してください)。
この同じトレース プロセスを適用して、任意の入力に対するパターンの動作を説明できます。