【问题标题】:How does non-backtracking subexpression work "(?>exp)"非回溯子表达式如何工作“(?> exp)”
【发布时间】:2012-07-24 13:45:17
【问题描述】:

我正在努力在正则表达式方面做得更好。我很难理解(?> expression ) 的含义。我在哪里可以找到有关非回溯子表达式的更多信息? THIS链接的描述说:

贪心子表达式,也称为非回溯子表达式。 仅匹配一次,然后不参与 回溯。

这个其他链接:http://msdn.microsoft.com/en-us/library/bs2twtah(v=vs.71).aspx 也有一个非回溯子表达式的定义但我仍然很难理解它的含义,而且我想不出一个我将使用 (?>exp) 的例子强>

【问题讨论】:

    标签: c# .net regex


    【解决方案1】:

    一如既往,regular-expressions.info 是一个不错的起点。

    如果您想确保曾经匹配的任何内容都将保留在匹配中,请使用原子组。

    例如,为了匹配可能由空格分隔或不由空格分隔的多个“单词”,然后是冒号,用户尝试了正则表达式:

    (?:[A-Za-z0-9_.&,-]+\s*)+:
    

    当有比赛时,一切都很好。但是,如果没有,他的 PC 会因为灾难性的回溯而在 100% 的 CPU 负载下变得无响应,因为正则表达式引擎会徒劳地尝试找到允许以下冒号匹配的单词的匹配组合。这当然是不可能的。

    通过使用原子组,本可以避免这种情况:

    (?>[A-Za-z0-9_.&,-]+\s*)+:
    

    现在任何匹配的东西都保持匹配 - 没有回溯,因此失败时间很快。

    我最近遇到的另一个好例子:

    如果您想匹配所有后面没有 ASCII 字母的数字,您可能需要使用正则表达式 \d+(?![A-Za-z])。但是,这会在输入 123a 时失败,因为正则表达式引擎会很高兴地通过回溯返回匹配 12,直到后面的字符不再是字母。如果您使用(?>\d+)(?![A-Za-z]),则不会发生这种情况。 (当然,\d+(?![\dA-Za-z]) 也可以)

    【讨论】:

    • 您最后的+ 是否仍然允许在“单词+空格”级别进行回溯?如果您在非捕获和+ 周围添加非回溯组,您将完全消除回溯。 (?>(?:[A-Za-z0-9_.&,-]+\s*)+):
    • 我认为你是对的。似乎许多现代正则表达式引擎确实在尝试开始漫长的回溯之旅之前就捕捉到了这些情况(“字面字符不存在”)。可怕的回溯主要是因为\s*,所以主要问题由我的正则表达式解决,但你的更彻底:)
    【解决方案2】:

    Regex 教程在这里有一个页面:http://www.regular-expressions.info/atomic.html

    基本上它的作用是丢弃回溯信息,这意味着a(?>bc|b)c 匹配abcc 但不匹配abc

    它与第二个字符串不匹配的原因是它找到了与bc 的匹配项,并丢弃了有关bc|b 替代的回溯信息。它基本上忘记了其中的|b 部分。所以bc后面没有c,匹配失败。

    使用原子组最有用的方法是优化慢正则表达式。您可以在上述页面上找到更多信息。

    【讨论】:

      【解决方案3】:

      阅读possessive quantifiers [a-z]*+ 使回溯引擎只记住匹配的上一步,而不是匹配的所有先前步骤。

      当可能有很多可接受的步骤时,这很有用,如果每个步骤都存储用于任何可能的回溯回归,它们会占用内存。

      所有格量词是原子团的简写。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-07-28
        • 1970-01-01
        • 2012-12-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多