【问题标题】:Negative lookbehind in regex正则表达式中的负向回溯
【发布时间】:2017-08-23 14:43:48
【问题描述】:

(注意:不是Why can't you use repetition quantifiers in zero-width look behind assertions 的重复项;见帖子末尾。)

我正在尝试编写一个匹配 B 的 grep -P (Perl) 正则表达式,但它前面没有 A——不管是否有中间空格。

所以,我尝试了这种消极的后视,并在 regex101.com 中对其进行了测试:

(?<!A)\s*B

这会导致“AB”不匹配,这很好,但“AB”确实会导致匹配,这不是我想要的。

我不确定这是为什么。它与\s*匹配空字符串“”这一事实有关,您可以说在A和B之间存在\s*的无限匹配。但是为什么这会影响“AB”但是不是“AB”?

下面的正则表达式是不是一个合适的解决方案,如果是,为什么它究竟能解决问题?

(?<![A\s])\s*B

我之前发布过此问题,但它被错误地标记为重复问题。我正在寻找的可变长度的东西是匹配的一部分,而不是本身的负面观察的一部分——所以这与另一个问题完全不同。是的,我可以将 \s* 放在否定的后面,但我没有这样做(并且不支持这样做,正如另一个问题所解释的那样)。另外,我对为什么我在上面发布的备用正则表达式有效特别感兴趣,因为我知道它有效,但我不确定为什么。另一个问题没有帮助回答这个问题。

【问题讨论】:

  • 你也可以使用/[^A\s]\s*B/
  • 好点。但在我的实际用例中,A 和 B 都是单词,而不仅仅是字符。
  • (?&lt;![A\s])\s*B 这不是一个好方法。原因之一是正在进行的巨大回溯。也许有一天你会更关心性能而不是实质。由于您使用的是 Perl,因此请利用它的动词。 (?:A\s*B(*SKIP)(*FAIL)|B)
  • 比较Regex1: (?&lt;![A\s])\s*B Completed iterations: 50 / 50 ( x 1000 ) Matches found per iteration: 1 Elapsed Time: 0.53 s, 530.18 ms, 530185 µs Regex2: (?:A\s*B(*SKIP)(*FAIL)|B) Completed iterations: 50 / 50 ( x 1000 ) Matches found per iteration: 1 Elapsed Time: 0.18 s, 180.07 ms, 180073 µs
  • @sln:特殊动词特别有用,因为它们可以在 A 和 B 是整个单词而不是字符时使用。

标签: regex perl grep negative-lookbehind


【解决方案1】:

但是为什么这会影响“AB”而不是“AB”呢?

正则表达式在 位置 匹配,将其视为字符之间会很有帮助。在 "AB" 中有一个位置(在空格之后和 B 之前)(?&lt;!A) 成功(因为前面没有 A;而是有一个空格),\s*B 成功(\s* 匹配空字符串,B 匹配 B),所以整个模式成功。

在“AB”中没有这样的位置。 \s*B 唯一可以匹配的地方(紧接在 B 之前),也是紧接在 A 之后,所以 (?&lt;!A) 不能成功。没有同时满足两者的位置,所以模式作为一个整体是不可能成功的。

下面的正则表达式是不是一个合适的解决方案,如果是,为什么它究竟能解决问题?

(?&lt;![A\s])\s*B

这是因为(?&lt;![A\s]) 不会在 A 之后立即成功 在空格之后。所以现在lookbehind禁止任何前面有空格的匹配位置。如果在 B 之前有个空格,它们必须被模式的\s* 部分消耗,并且匹配位置必须在它们之前。如果该位置之前没有 A,则后向可以成功并且整个模式可以匹配。

这是一个技巧,因为\s 是一个固定宽度的模式,匹配非空\s* 匹配内的每个 位置。它不能扩展到(非)A和B之间的any模式的一般情况。

【讨论】:

  • 有道理,谢谢!回复:您的第一点:我花了一分钟才意识到“所以 (?
  • 总结一下,对于任何正在阅读本文并感到困惑的人:对于原始正则表达式,“AB”是一个棘手的情况,因为在 B 之前有一个潜在的匹配位置,其中 \s* 就像一个空字符串并且有一个前面的空格,而不是前面的 A,所以否定的lookbehind 不会禁止匹配。为了解决这个问题,更改后的正则表达式确保只考虑不直接在空格之后的匹配位置。
  • @wdep1 有效点!我将“匹配”更改为“成功”,希望更清晰(否定环视通过不匹配任何内容而成功)。
猜你喜欢
  • 1970-01-01
  • 2012-12-06
  • 1970-01-01
  • 2020-06-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多