regex - 关于问号 "lazy"模式的正则表达式

标签 regex regex-greedy non-greedy

我理解 ? 标记在这里表示“懒惰”。

我的问题本质上是 [0-9]{2}?[0-9]{2}

它们一样吗?
如果是这样,我们为什么要写前一个表达式?惰性模式不是更昂贵的性能吗?
如果不是,你能说出区别吗?

最佳答案

什么是“惰性”(勉强)匹配?

与正则表达式匹配时,指针默认贪心:

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>"!

什么可以量化为懒惰?

您可以添加 ?在量词和范围后面构造:

+ (一个或多个),* (零个或多个),? (可选);
{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. 精确范围量词不受影响。
    X{n}之间和 X{n}? ,几乎没有区别;大多数引擎在内部优化掉了不情愿的标志。这是因为惰性构造仅在匹配是动态的情况下适用,其中引擎可以针对量词(需要或贪婪)以一种或另一种方式表现,但不适用于这种情况。

查看 regex101 ,一个完善的正则表达式引擎,附带解释和调试器日志,向您展示指针步骤。 另请阅读 The Stack Overflow Regex Reference !

关于regex - 关于问号 "lazy"模式的正则表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25728576/

相关文章:

java - 将 ' (single quote once) but not ' '(单引号两次)替换为 '||' '' 的正则表达式

javascript - 油猴Javascript : how to loop through all text and change only whole words?

regex - 如何在这个给定的场景中应用惰性量词?

数字和空格的正则表达式作为千位分隔符

regex - 非贪婪正则表达式根据原子在正则表达式中的位置表现贪婪

java - 正则表达式匹配单个字符

regex - Mod重写正则表达式负前瞻

javascript - 为什么正则表达式.*? javascript中只匹配空字符串?

java - 为什么这个非贪婪的正则表达式比我想要的要多?

java - java htmlunit 中的正则表达式