展开循环,何时使用

时间:2016-06-24 16:34:48

标签: javascript regex

我试图理解正则表达式中的展开循环。有什么区别:

MINISTÉRIO[\s\S]*?PÁG

MINISTÉRIO(?:[^P]*(?:P(?!ÁG\s:\s\d+\/\d+)[^P]*)(?:[\s\S]*?))PÁG

在此背景下:

http://regexr.com/3dmlr

为什么我要使用第二个,如果第一个做同样的事情?

感谢。

1 个答案:

答案 0 :(得分:4)

什么是Unroll-the-loop

请参阅此Unroll the loop technique来源:

  

此优化技术用于优化形式(expr1|expr2|...)*的重复交替。这些表达并不罕见,并且在交替中使用另一次重复也可能导致超线性匹配。超线性匹配来自不确定性表达式(a*)*

     

展开循环技术是基于这样的假设:在大多数情况下,你在重复的交替中,这种情况应该是最常见的,哪一种是例外的。我们将调用第一个,正常情况和第二个,特殊情况。然后,展开循环技术的一般语法可以写成:

     

正常*(特殊正常*)*

所以,这是一个优化技术,其中交替变成线性匹配的原子。

这使得这些展开的模式非常有效,因为它们涉及较少的回溯。

当前场景

您的MINISTÉRIO[\s\S]*?PÁG是未展开的模式,MINISTÉRIO[^P]*(?:P(?!ÁG)[^P]*)*PÁG是。查看演示(两者都保存了PCRE选项以显示上面框中的步骤数。正则表达式引擎的正则表达式性能不同,但这将告诉您确切的性能差异)。在text之后添加更多文字:第一个正则表达式将开始需要更多步骤才能完成,第二个正则表示只会在添加P后显示更多步骤。因此,已知部分中使用的字符不常见的文本中,展开的模式非常有效

请参阅我的回答中的Difference between .*?, .* and [^"]*+ quantifiers部分,了解延迟匹配的工作原理([\s\S]*?.*?相同,其中DOTALL修饰符的语言允许.也匹配换行符。)

表现问题

延迟匹配模式总是缓慢且低效吗?并非总是如此。对于非常短的字符串,惰性点匹配通常更好(1-10个符号)。当我们谈论长输入时,可能存在前导分隔符,而没有尾随分隔符,这可能导致过度回溯导致超时问题。

如果您有任意长度的输入且可能无法匹配,请使用展开的模式。

在您的输入受到控制时使用延迟匹配,您知道总会有匹配,某些已知的设置日志格式等。

奖励:通常展开的模式

  1. Tempered greedy tokens

  2. 常规字符串文字("String\u0020:\"text\""):"[^"\\]*(?:\\.[^"\\]*)*"

  3. 多行注释正则表达式{/* Comments */):/\*[^*]*\*+(?:[^/*][^*]*\*+)*/

  4. @<...>@评论正则表达式:@<[^>]*(?:>[^@]*)*@