【问题标题】:Regular Expression Lookbehind doesn't work with quantifiers ('+' or '*')正则表达式 Lookbehind 不适用于量词(“+”或“*”)
【发布时间】:2012-02-20 06:22:43
【问题描述】:

我正在尝试在正则表达式中使用lookbehinds,但它似乎没有像我预期的那样工作。所以,这不是我真正的用法,但为了简化我会举一个例子。想象一下,我想在“这是一个示例”的字符串上匹配“示例”。所以,根据我对lookbehinds的理解,这应该可行:

(?<=this\sis\san\s*?)example

这应该做的是找到“this is an”,然后是空格字符,最后匹配单词“example”。现在,它不起作用,我不明白为什么,不可能在lookbehinds中使用'+'或'*'?

我也尝试了这两个,它们可以正常工作,但不能满足我的需求:

(?<=this\sis\san\s)example
this\sis\san\s*?example

我正在使用这个网站来测试我的正则表达式:http://gskinner.com/RegExr/

【问题讨论】:

  • 这需要一个标签来标识您使用它们的语言或环境。 .NET 的正则表达式可以毫无问题地处理这个问题。
  • 注意!如果你的正则表达式能像你想要的那样工作,它也将匹配examplethis is anexample。所以如果你不想这样,你应该删除?
  • micha:他们可能应该只是将 * 更改为 +。删除 ? 在这方面没有任何影响。但实际上,*? 作为量词在这种情况下是无用且不必要的,因为在那之后没有更多的空格可以匹配,所以\s*? 等同于\s*

标签: regex lookbehind


【解决方案1】:

嘿,如果您不使用 python 变量查找断言后面,您可以通过转义匹配并使用 \K 重新开始来欺骗正则表达式引擎。

这个网站解释得很好..http://www.phpfreaks.com/blog/pcre-regex-spotlight-k..

但是当你有一个匹配的表达式并且你想使用 \K 得到它背后的所有东西时,几乎会迫使它重新开始......

例子:

string = '<a this is a tag> with some information <div this is another tag > LOOK FOR ME </div>'

匹配/(\&lt;a).+?(\&lt;div).+?(\&gt;)\K.+?(?=\&lt;div)/ 将导致正则表达式在匹配结束div 标记后重新启动,因此正则表达式不会将其包含在结果中。 (?=\div) 将使引擎在结束 div 标签之前获取所有内容

【讨论】:

  • 这适用于 ruby​​ 2.x,但适用于 1.9 和 jruby 1.7.x;原评论:好一个,我很惊讶我从来不知道这个功能。学会在编辑器中格式化代码,你会是无价的
【解决方案2】:

您可以使用子表达式。

(this\sis\san\s*?)(example)

所以要检索第 2 组,“示例”,$2 用于正则表达式,或者\2,如果您使用的是格式字符串(如 python 的 re.sub

【讨论】:

    【解决方案3】:

    许多正则表达式库只允许在后面断言中使用严格表达式,例如:

    • 只匹配相同固定长度的字符串:(?&lt;=foo|bar|\s,\s)(每个三个字符)
    • 只匹配固定长度的字符串:(?&lt;=foobar|\r\n)(每个分支固定长度)
    • 仅匹配具有上限长度的字符串:(?&lt;=\s{,4})(最多重复四次)

    这些限制的原因主要是因为这些库根本无法向后处理正则表达式或只能处理有限的子集。

    另一个原因可能是避免作者构建过于复杂而难以处理的正则表达式,因为它们有一个所谓的pathological behavior(另请参阅ReDoS)。

    另见section about limitations of look-behind assertionsRegular-Expressions.info

    【讨论】:

    • my answer to this question 中,我列出了一些策略/解决方法,因为我遇到了负面回溯的限制。希望它也可以帮助其他人!
    【解决方案4】:

    大多数正则表达式引擎不支持后向断言的可变长度表达式。

    【讨论】:

    • 只有后视才有问题。 Lookahead 可以是所有支持它的正则表达式引擎中的任何内容。
    【解决方案5】:

    Amber 说的是真的,但您可以使用另一种方法解决它:非捕获括号组

    (?<=this\sis\san)(?:\s*)example
    

    这使它成为一个 固定 长度向后看,所以它应该可以工作。

    【讨论】:

    • 它与(?&lt;=this\sis\san)\s*?example 相同,这意味着它也匹配空格,并且供您参考(?: ) 使过程变慢。
    • micha,在这种情况下,我更担心匹配部分而不是性能。使用非捕获组我平均得到 0.02451781 毫秒,而没有它则平均得到 0.02370844 毫秒。我不认为这是一个显着的区别。
    • @micha 不,不一样。这是一个非捕获组。我的正则表达式仅匹配 example(没有前导空格),但您的示例 includes 前导空格
    • 这个正则表达式将匹配任何前面的空格。例如this is an[ example]。 (方括号表示匹配)。仅仅因为它在非捕获组中,并不意味着它不匹配。这只是意味着它没有被捕获在通常会在正常括号中捕获的组中。正确的方法是使用\K 就像@Leon 说的那样
    • 这不起作用。匹配中包含前导空格。只需复制并粘贴到regex101.com
    猜你喜欢
    • 2012-02-08
    • 2021-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-01
    • 1970-01-01
    相关资源
    最近更新 更多