【问题标题】:What is the difference between `Greedy` and `Reluctant` regular expression quantifiers?`Greedy` 和 `Reluctant` 正则表达式量词有什么区别?
【发布时间】:2009-07-16 17:43:29
【问题描述】:

来自Patternjavadocs:

贪心量词: X? X,一次或一次 X* X,零次或多次 X+ X,一次或多次 X{n} X,正好 n 次 X{n,} X,至少 n 次 X{n,m} X,至少 n 次但不超过 m 次 不情愿的量词: X?? X,一次或一次 X*? X,零次或多次 X+? X,一次或多次 X{n}? X,正好 n 次 X{n,}? X,至少 n 次 X{n,m}? X,至少 n 次但不超过 m 次

他们所做的描述都是一样的……那么,有什么区别呢?

我真的很感激一些例子。

我正在使用 Java 进行编码,但我听说这个概念对于大多数现代正则表达式实现都是相同的。

【问题讨论】:

  • FWIW:这个问题的“in Java”部分有点无关紧要。贪婪与不情愿的量词在几乎任何正则表达式实现中都意味着同样的事情。在大多数现代实现中,语法甚至几乎相同:Java 模式实际上是根据 Perl 正则表达式建模的,您会通过 PCRE 在 Python、Ruby 甚至 C/C++ 中找到相同的东西。

标签: java regex


【解决方案1】:

一个贪婪的算子总是试图“抓住”尽可能多的输入,而一个不情愿的量词会尽可能少地匹配输入,但仍然会创建一个匹配项。

例子:

"The red fox jumped over the red fence"
/(.*)red/ => \1 = "The red fox jumped over the "
/(.*?)red/ => \1 = "The "

"aaa"
/a?a*/ => \1 = "a", \2 = "aa"
/a??a*/ => \1 = "", \2 = "aaa"

"Mr. Doe, John"
/^(?:Mrs?.)?.*\b(.*)$/ => \1 = "John"
/^(?:Mrs?.)?.*?\b(.*)$/ => \1 = "Doe, John"

【讨论】:

    【解决方案2】:

    来自this link,教程作者承认您的问题的精神:

    乍一看似乎 量词 X?, X??和 X?+ 做 完全相同的东西,因为他们都 承诺匹配“X,一次或不匹配 全部”。有微妙的实现 差异将被解释 接近本节的结尾。

    他们继续整理示例并提供解释:

    考虑贪婪量词 “贪婪”,因为他们强迫 matcher 读入或吃掉整个 在尝试之前输入字符串 第一场比赛。如果第一场比赛 尝试(整个输入字符串) 失败,匹配器退出输入 一个字符的字符串并尝试 再次,重复该过程,直到 找到匹配项或没有更多匹配项 离开的字符。 取决于使用的量词 表达,最后一件事 尝试匹配是 1 或 0 字符。

    然而,勉强的量词, 采取相反的方法:他们开始 在输入字符串的开头, 然后不情愿地吃掉一个字符 寻找比赛的时间。最后 他们尝试的是整个输入 字符串。

    为了额外的荣誉,所有格解释:

    最后,所有格量词 总是吃掉整个输入字符串, 尝试一次(且仅一次) 匹配。与贪心量词不同, 所有格量词从不退缩, 即使这样做会让 整体匹配成功。

    【讨论】:

    • 感谢您也添加了有关所有格的信息。
    【解决方案3】:

    一个贪婪的量词会尽可能地匹配并且仍然得到匹配 不情愿的量词将匹配尽可能小的数量。

    例如给定字符串

    abcdef

    贪婪的限定符

    ab[a-z]*[a-z] 将匹配 abcdef

    不情愿的限定词

    ab[a-z]*?[a-z] 将匹配 abc

    【讨论】:

    • 其实贪心字符类会匹配“cde”,因为a匹配a,b匹配b,最后一个[a-z]匹配f。不情愿的字符组会匹配完全一样的东西
    • @Machine:你错了,[a-z]*?[a-z] 会总是 匹配first [a-z] 字符! 1. [a-z]*?首先跳转到下一条规则:[a-z],如果不匹配,则 [a-z]*?也不匹配,这就是故事的结局。但是 2. 如果 [a-z] 匹配,每个人都很高兴...
    【解决方案4】:

    假设你有一个正则表达式"a\w*b",并在"abab" 上使用它 贪婪匹配将匹配"abab"(它会寻找a,尽可能多地出现\w,以及b)并且不情愿匹配将仅匹配"ab"(尽可能少的\w

    【讨论】:

      【解决方案5】:

      有关于 Perl 如何处理这些量词 perldoc perlre 的文档。

      默认情况下,量化的子模式是“贪婪的”,也就是说,它会尽可能多地匹配(给定一个特定的起始位置),同时仍然允许模式的其余部分匹配。如果您希望它匹配尽可能少的次数,请在量词后面加上“?”。请注意,含义不会改变,只是“贪婪”:
          *?     Match 0 or more times, not greedily
          +?     Match 1 or more times, not greedily
          ??     Match 0 or 1 time, not greedily
          {n}?   Match exactly n times, not greedily
          {n,}?  Match at least n times, not greedily
          {n,m}? Match at least n but not more than m times, not greedily
      
      默认情况下,当量化的子模式不允许整个模式的其余部分匹配时,Perl 将回溯。但是,这种行为有时是不可取的。因此 Perl 也提供了“占有”量词形式。
          *+     Match 0 or more times and give nothing back
          ++     Match 1 or more times and give nothing back
          ?+     Match 0 or 1 time and give nothing back
          {n}+   Match exactly n times and give nothing back (redundant)
          {n,}+  Match at least n times and give nothing back
          {n,m}+ Match at least n but not more than m times and give nothing back
      
      例如,
         'aaaa' =~ /a++a/
      
      永远不会匹配,因为 a++ 将吞噬字符串中的所有 a ,并且不会为模式的其余部分留下任何内容。这个特性对于给 perl 提示它不应该回溯的地方非常有用。例如,典型的“匹配双引号字符串”问题在写成时可以最有效地执行:
         /"(?:[^"\\]++|\\.)*+"/
      
      我们知道,如果最终报价不匹配,回溯将无济于事。更多细节见独立子表达式(?>...);所有格量词只是该结构的语法糖。例如上面的例子也可以写成如下:
         /"(?>(?:(?>[^"\\]+)|\\.)*)"/
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-03-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-10
        • 2013-11-09
        • 2013-10-07
        • 2013-04-16
        相关资源
        最近更新 更多