为什么Negative Lookahead会因And / Or Pipe而超时

时间:2016-09-15 04:02:57

标签: python regex timeout negative-lookahead

我有一个和/或正则表达式(PatternA | PatternB),其中我只采用PatternA,如果PatternB不存在(PatternB总是在PatternA之后,但更重要),所以我在PatternA管道中放了一个负面的预测。 / p>

这适用于较短的文本块:

https://regex101.com/r/bU6cU6/5

但是在较长的文本块上超时:

https://regex101.com/r/bU6cU6/2

我不明白的是,如果我将PatternA与Neg Look放在同一个长文本块中,只需要32步就可以拒绝它:

https://regex101.com/r/bU6cU6/3

如果我将PatternB单独放在同一个长文本块中,则只需要18步即可接受它:

https://regex101.com/r/bU6cU6/4

所以我不确定为什么要先扣除100,000步/超时(32步)然后接受(18步)管道。是否有其他/更好的方法来构建,因此它首先检查PatternA而不是PatternB,因为现在它正在做一些我不理解从50步到100k +的事情。

2 个答案:

答案 0 :(得分:1)

与"全球"一起使用的非固定外观。正则表达式(匹配多次出现)导致过多的工作,并且效率低下。他们应该是#34;锚定"在一些具体的背景下。通常,它们在字符串的开头(前瞻)或结束(lookbehinds)处执行。

在你的情况下,你可以"锚定"它放在Option1:之后,以确保它仅在Option1:匹配后执行。

Option1:(?!.*Option2)\*.*?(?P<Capture>Bob|David|Ted|Alice)|\*Option2 (?P<Capture2>Juan)
        ^^^^^^^^^^^^^

请参阅this regex demo

更多答案:

  

我不明白的是,如果我将PatternA与Neg Look放在同一个长文本块中,只需要32步就可以拒绝它

是的,但您通过内部优化测试了它。禁用它们,您将看到

enter image description here

  

如果我将PatternB单独放在同一个长文本块中,它只需要18步就可以接受它:

以预期的方式找到匹配,非常有效:

enter image description here

答案 1 :(得分:1)

你的主要问题是前瞻的位置。必须在每个位置尝试前瞻,并且每次都必须扫描所有剩余的字符。较长的测试字符串长度超过3500个字符;加起来。

如果你的正则表达式没有锚定,你应该总是试着用一些失败或快速成功的具体事物来启动它 - 文字文本是最好的。在这种情况下,显而易见的是,您可以向前移动前瞻:Option1:\*(?!.*Option2)而不是(?!.*Option2)Option1:\*。 (注意前瞻中没有尾随.*;你不需要它。)

但是当你单独匹配时,为什么PatternA会更快?内部优化。当正则表达式只是(?!.*Option2.*)Option1:\*.*?(?P<Capture>(Bob|David|Ted|Alice))时,正则表达式引擎可以告诉匹配必须以Option1:*开头,因此它会直接进入第一次匹配尝试的位置。正则表达式越长越复杂,优化就不会发生。

您可以使用Regex101中的“regex debugger”选项进行测试,然后选中DISABLE INTERNAL ENGINE OPTIMIZATIONS。步数可以追溯到100,000以上。