为什么/ \ w +:/和/ \ S +:/处理回溯不同?

时间:2015-11-14 07:33:26

标签: regex pcre backtracking

我使用regex101分析了这两个正则表达式。我认为/\S+:/的回溯是正确的。但我无法理解这种差异。我错了吗?

regex101.com

2 个答案:

答案 0 :(得分:15)

这是名为auto-possessification的{​​{3}}优化。

来自

  

PCRE"自动拥有"优化通常适用于   字符在模式的末尾(以及内部)重复。对于   例如,模式" a\d+"编译好像是" a\d++"因为   即使考虑回溯的可能性也没有意义   重复数字。

  

这是一项优化,例如,将a+b转换为a++b   为了避免回溯到永远无法成功的a+

由于:中未包含\w,因此您的模式被解释为\w++:(第二个+会阻止回溯,http://pcre.org/pcre.txt)。避免了额外的回溯状态,因为它没有可能匹配的另一个状态。

另一方面,:中包含\S,因此此优化不适用于第二种情况。

PCRETEST

您可以使用see possessive quantifiers(您可以下载pcretest的Windows版本)查看差异。

模式/\w+:/需要 11步并输出:

/\w+:/
--->get accept:
 +0 ^               \w+
 +3 ^  ^            :
 +0  ^              \w+
 +3  ^ ^            :
 +0   ^             \w+
 +3   ^^            :
 +0    ^            \w+
 +0     ^           \w+
 +3     ^     ^     :
 +4     ^      ^    .*
 +6     ^      ^    
 0: accept:

但是,如果我们使用控制动词 here 来禁用此优化,则模式/(*NO_AUTO_POSSESS)\w+:/需要 14步并输出:< / p>

/(*NO_AUTO_POSSESS)\w+:/
--->get accept:
+18 ^               \w+
+21 ^  ^            :
+21 ^ ^             :
+21 ^^              :
+18  ^              \w+
+21  ^ ^            :
+21  ^^             :
+18   ^             \w+
+21   ^^            :
+18    ^            \w+
+18     ^           \w+
+21     ^     ^     :
+22     ^      ^    .*
+24     ^      ^    
 0: accept:

- 正如预期的那样,它比\S+少1步,因为\w+:不匹配。

不幸的是(*NO_AUTO_POSSESS)不支持此动词。

更新: regex101现在支持此动词,这里有3个要比较的案例的链接:

  1. /\S+:/(14个步骤) - regex101

  2. /\w+:/(10个步骤) - https://regex101.com/r/cw7hGh/1/debugger

  3. /(*NO_AUTO_POSSESS)\w+:/(13个步骤) - https://regex101.com/r/cw7hGh/2/debugger

  4. regex101调试器:

    https://regex101.com/r/cw7hGh/3/debugger

答案 1 :(得分:11)

虽然这似乎是特定于实现的(RegexBuddy没有显示此行为),但可以解释如下:

\w无法匹配:,但\S可以。因此,\S+:需要检查输入字符串的更多变体,然后才能确保get无法与之匹配。

更优化的正则表达式引擎将更快地排除不可能的匹配(例如,当正则表达式包含匹配的当前部分中不存在的文字字符时),但显然regex101正在使用的引擎不这样做。