2

?ここのマークが「怠け者」を意味することは理解しています。

私の質問は本質的に[0-9]{2}?vsです[0-9]{2}

それらは同じですか?
もしそうなら、なぜ前者の式を書いているのでしょうか? レイジー モードはよりコストのかかるパフォーマンスではありませんか?
そうでない場合、違いを教えていただけますか?

4

2 に答える 2

8

「怠け者」(消極的) マッチングとは?

正規表現と一致する場合、ポインターはデフォルトで貪欲です。

Left | Right
\d+    12345
^      ^
\d+    12345
  ^    ^^^^^ Matched!

怠惰は貪欲の反対です。

Left | Right
\d+?   12345
^      ^
\d+?   12345
  ^^    ^
       12345
         ^
       12345
          ^
       12345
           ^ Matched!

なぜそれが重要なのですか?

一致では、量指定子* + ?はデフォルトで貪欲です。これは望ましくない動作につながる可能性があります。特に、一致が完了するために必要な場合にのみ特定の文字を一致させ、それ以外の場合は省略したい場合です。

典型的な例は、単一の XML タグに一致させたい場合です。これは で失敗し<.*>ます。

Left | Right
<.*>   <p>hi</p><br /><p>bye</p>
^      ^
<.*>   <p>hi</p><br /><p>bye</p>
 ^^     ^^^^^^^^^^^^^^^^^^^^^^^^
<.*>   <p>hi</p><br /><p>bye</p>
   ^                           < [backtrack!]
<.*>   <p>hi</p><br /><p>bye</p>
   ^                           ^ Matched "<p>hi</p><br /><p>bye</p>"!
Left* | Right
<.*?>   <p>hi</p><br /><p>bye</p>
^       ^
<.*?>   <p>hi</p><br /><p>bye</p>
 ^^^     ^ [can we stop? we're lazy [yes]]
<.*?>   <p>hi</p><br /><p>bye</p>
    ^     ^ Matched "<p>"!

何を怠け者と見なすことができますか?

?数量詞と範囲の後ろに構文を追加できます。

+(1 つ以上)、*(ゼロ以上)、?(オプション);
{n,m}(n と m の間、n < m)、{n,}(n 以上)、{n}(正確に n 回)。
(例中の n と m は実数で、n, m ϵ Nを満たす)

  1.     気が進まない量指定子は、先に進みたがりません。エンジンは、残りの部分が成功するために絶対に必要な場合に
    のみ一致を試行するという考慮の下で、可能な限り多くまたはできるだけ少なく一致することが許可されます。次のケースを参照してください。

    Left | Right
    abc*   abccccd
    ^      ^
    abc*   abccccd
     ^      ^
    abc*   abccccd
      ^      ^
    abc*   abccccd
      ^^     ^^^^ Matched "abcccc"!
    
    Left* | Right
    abc*?   abccccd
    ^       ^
    abc*?   abccccd
     ^       ^
    abc*?   abccccd
      ^^^     ^ [must we do this? we're lazy [no]]
               Matched "ab"!
    

    示されているように、それらは可能な限り一致しません。

  2.     気が進まない量指定子は、他の量指定子を楽しませることをあきらめます。
    (デモンストレーション目的; 誰かが尋ねたとしても、このように RegExp を使用しても問題ないとは言いませんでした。)

    Left | Right
    c+c+   abccccd
    ^        ^
    c+c+   abccccd
    ^^       ^^^^
    c+c+   abccccd
      ^         < [backtrack]
    c+c+   abccccd
      ^^        ^ Matched "cccc"!
                  (c+ -> @ccc; c+ -> @c)
    
    Left* | Right
    c+?c+   abccccd
    ^         ^
    c+?c+   abccccd
    ^^^       ^ [pass]
    c+?c+   abccccd
       ^^      ^^^ Matched "cccc"!
                   (c+? -> @c; c+ -> @c)
    
  3.     正確な範囲量指定子は影響を受けません。との
    間には、実質的に違いはありません。また、ほとんどのエンジンは、消極的なフラグを内部的に最適化します。これは、一致が動的である場合にのみ遅延構造が適用されるためです。この場合、エンジンは量指定子 (need または greed) に対していずれかの方法で動作できますが、この場合には適用できません。X{n}X{n}?

よくできた正規表現エンジンであるregex101を確認してください。このエンジンには、説明とポインターの手順を示すデバッガー ログが付属しています。スタック オーバーフロー正規表現リファレンスもお読みください。

于 2014-09-08T18:43:52.387 に答える
5

と の間に違いはありません[0-9]{2}[0-9]{2}?

貪欲なマッチングと怠惰なマッチング ( a の追加) の違い?は、バックトラッキングに関係しています。正規表現エンジンは、テキスト (左から右)に一致するように構築されています。したがって、ある範囲の文字に一致する式を要求すると、可能な限り多くの文字に一致するのは論理的です。


string があるとしますacac123

[a-z]+c(+は 1 回以上の繰り返しまたは)の貪欲な一致を使用する場合{1,}:

  • [a-z]+で一致acacし、失敗します1
  • 次に、 を一致させようとしますcが、 で失敗します1
  • ここでバックトラックを開始し、正常に一致acaしてc

これを遅延 ( [a-z]+?c) にすると、異なる応答 (この場合) が得られ、より効率的になります。

  • [a-z]+?と一致aしますが、次の文字が式の残りの部分と一致するため停止しますc
  • その後、c一致し、正常に一致aし、c(バックトラッキングなしで)

これで、 と の間に違いがないことがわかります。 は範囲ではなく、貪欲な一致でもバックトラッキングが発生しないためです。遅延一致は(0+ 繰り返しまたは) またはでよく使用されますが、範囲で使用することもできます(はオプションです)。X{#}X{#}?{#}*{0,}+{m,n}n

これは、可能な限り少ない文字数で一致させたい場合に不可欠であり、(文字列の).*?スペースを埋めたい場合に式でよく見かけます。ただし、多くの場合、遅延一致は悪い/非効率的な正規表現の例です。多くの人は、二重引用符で囲まれたすべてのものに一致するようなことします.foo.*?barfoo bar filler text barfoo:"(.*?)"foo:"([^"]+)" "


最後のメモは、?通常、「オプション」または試合{0,1}時間を意味します。範囲 ( 、、、または別の)?で使用する場合にのみ、一致を遅延させます。これは、怠け者にならないことを意味します(すでに言ったように無意味です) が、代わりにオプションになります。ただし、レイジーな「オプションの」マッチを行うことができます: レイジーに0-1 回マッチします。{m,n}*+?X?X{#}?[0-9]??

于 2014-09-08T18:38:06.083 に答える