25

最近、PCRE- (Perl 互換の正規表現) のドキュメントを読んでいて、正規表現を使った興味深いトリックに出くわしました。(*...)読み続けて疲れ果てたので、いくつかのパターンを使用することに関連して混乱したため、やめました。

私の質問と混乱は(*PRUNE)(*FAIL)

参考までに(*SKIP)のように動作(*PRUNE)しますが、パターンが固定されていない場合、バンパロングは次の文字ではなく、遭遇した対象の位置(*SKIP)に進みます。

ドキュメントには、パターンの残りの部分が一致しない場合、サブジェクトの現在の開始位置(*PRUNE)で一致が失敗する原因になると記載されています。そして、それは否定的な主張と同義であると述べています。パターン内の指定された位置でマッチングの失敗を強制します。(*FAIL)(?!)

したがって、基本的に(*FAIL)は失敗した否定的なアサーションのように動作し、(?!)

そして、バックトラッキングがそれに到達する原因となる後で一致の失敗がある場合、件名(*PRUNE)の現在の開始位置で一致が失敗します。

失敗のポイントになると、これらはどのように異なりますか?

これらがどのように実装され、正しく使用されているかの例を誰でも提供できますか?

4

1 に答える 1

37

この回答を読む前に、バックトラック、アトミック グループ、および所有量指定子のメカニズムに精通している必要があります。これらの概念と機能に関する情報は、Friedl の本と次のリンクにあります: www.regular-expressions.infowww.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)

于 2013-11-15T19:12:24.417 に答える