この回答を読む前に、バックトラック、アトミック グループ、および所有量指定子のメカニズムに精通している必要があります。これらの概念と機能に関する情報は、Friedl の本と次のリンクにあります: www.regular-expressions.info、www.rexegg.com
すべてのテストは、グローバル検索 (preg_match_all()
関数を使用) で行われています。
(*FAIL)
(または省略形(*F)
)
baabo caaco daado
caac(*FAIL)|aa.|caaco|co
[0] => aab
[1] => caaco
[2] => aad
(*FAIL)
パターン内の「悪い文字」とまったく同じ動作を引き起こします。たとえば、これを「R」に置き換えると、まったく同じ結果が得られますcaacR|aa.|caaco|co
。より一般的に言うと、次(*FAIL)
のような「常に失敗するサブパターン」に実際に置き換えることができます: (?!)
, (?=a(?<!a))
,...
a (first from "baabo")
: 当然のことながら、最初の結果は 2 番目の選択肢によって検出されます。( aab
)
c (first)
: 正規表現エンジンは最初の "c" に遭遇し、最初の選択肢を試みて : を見つけますcaac
が、サブパターンは強制的に失敗します。次に、正規表現エンジン (常に最初の "c" から) は、失敗した 2 番目の選択肢を試行し、3 番目の選択肢は成功します。( caaco
)
a (first from "daado")
: 3 番目の結果は 2 番目の選択肢によって見つかります。( aad
)
(*SKIP)
baabo caaco daado
caa(*SKIP)c(*FAIL)|aa.|caaco|co
[0] => aab
[1] => co
[2] => aad
この動詞は、サブパターンが後で失敗したときに正規表現エンジンがバックトラックを許可されないポイントを定義します。その結果、サブパターンで以前に見つかったすべての文字が一度だけ消費され、パターンの別の部分 (代替) に使用できなくなります。
a (first from "baabo")
: 最初の結果は 2 番目の選択肢によって検出されます。( aab
)
c (first)
: 正規表現エンジンはcaac
最初のケースのように検出し、(動詞が原因で) 失敗(*FAIL)
し、2 番目の "c" に戻りますが、動詞の前に以前に一致した文字 ("caa") に戻ることはできません(*SKIP)
。
c (second)
: 現在、正規表現エンジンは常に最初の選択肢を試みますが、この新しい位置では、後に「a」ではなく「o」があるため失敗し、この 2 番目の「c」に戻ります。この場合、(*SKIP)
動詞に到達する前にサブパターンが失敗したため、これらの文字は以前のように消費されないことに注意してください。2 番目の選択肢はテストされ、失敗します ("c" で始まらない)。次の文字が「a」ではなく「o」であるため、3 番目の選択肢も失敗します。4 番目の選択肢は成功し、2 番目の結果が得られます。co
( )
a (first from "daado")
: 3 番目の結果は 2 番目の選択肢によって見つかります。( aad
)
(*PRUNE)
baabo caaco daado
caa(*PRUNE)c(*FAIL)|aa.|caaco|co
[0] => aab
[1] => aac
[2] => aad
この動詞は(*SKIP)
、以前に一致したすべての文字の使用を禁止するわけではありませんが、サブパターンが後で失敗する場合、サブパターンによって最初に一致した文字をスキップする (またはサブパターンの開始を禁止する) ため、 とは異なります。
a (first from "baabo")
: 最初の結果は 2 番目の選択肢によって検出されます。( aab
)
c (first)
: 正規表現エンジンはcaac
最初のケースのように検出し、その後失敗しますが、最初の "c" がスキップされるため、"caaco" から最初の "a" にバックトラックします。
a (first from "caaco")
: 最初の選択肢が試行されて失敗し、2 番目の選択肢が成功して 2 番目の結果が得られます。( aac
)
a (first from "daado")
: 3 番目の結果は 2 番目の選択肢によって見つかります。( aad
)