Regex 为什么/\w+;:/和/\S+;:/以不同的方式处理回溯?

Regex 为什么/\w+;:/和/\S+;:/以不同的方式处理回溯?,regex,pcre,backtracking,Regex,Pcre,Backtracking,我分析了这两个正则表达式使用。我认为/\S+:/的回溯是正确的。但我不能理解这种区别。我错了吗 虽然这似乎是特定于实现的(RegexBuddy不显示此行为),但可以解释如下: \w无法匹配:,但\S可以。因此,\S+:需要检查输入字符串的更多变体,然后才能确保get无法匹配它 更优化的正则表达式引擎将更快地排除不可能的匹配(例如,当正则表达式包含的文字字符在匹配的当前部分中不存在时),但显然正则表达式101使用的引擎没有这样做。这是一种称为自动占有的优化 发件人: PCRE的“自动占有”优化通常

我分析了这两个正则表达式使用。我认为
/\S+:/
的回溯是正确的。但我不能理解这种区别。我错了吗


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

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

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

这是一种称为
自动占有的优化

发件人:

PCRE的“自动占有”优化通常适用于 字符在模式末尾重复(以及在内部)。对于 例如,模式“
a\d++
”被编译为“
a\d++
”,因为 甚至考虑回溯的可能性都没有意义 输入重复的数字

这是一种优化,例如,将
a+b
转换为
a++b
为了避免返回到永远不会成功的
a+

由于
未包含在
\w
中,因此您的模式被解释为
\w++:
(第二个
++
防止回溯,)。避免了额外的回溯状态,因为没有其他可能匹配的状态

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


复测 您可以使用(您可以下载Windows版本)查看差异

模式
/\w+://
采取11个步骤并输出:

/\w+:/
--->get accept:
 +0 ^               \w+
 +3 ^  ^            :
 +0  ^              \w+
 +3  ^ ^            :
 +0   ^             \w+
 +3   ^^            :
 +0    ^            \w+
 +0     ^           \w+
 +3     ^     ^     :
 +4     ^      ^    .*
 +6     ^      ^    
 0: accept:
/(*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:
但是,如果我们使用控制动词,它将禁用此优化,则模式
/(*NO\u AUTO\u have)\w+:/
将执行14个步骤并输出:

/\w+:/
--->get accept:
 +0 ^               \w+
 +3 ^  ^            :
 +0  ^              \w+
 +3  ^ ^            :
 +0   ^             \w+
 +3   ^^            :
 +0    ^            \w+
 +0     ^           \w+
 +3     ^     ^     :
 +4     ^      ^    .*
 +6     ^      ^    
 0: accept:
/(*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+
不匹配


不幸的是,它不支持这个动词

更新:regex101现在支持这个动词,下面是指向要比较的3种情况的链接:

  • /\S+:/
    (14个步骤)-

  • /\w+:/
    (10个步骤)-

  • /(*无自动拥有)\w+:/
    (13个步骤)-

  • regex101调试器:


    我真的很好奇你是如何一步一步地做到这一点的,这样你就可以分析它了@Mehrdad:在regex101.com上,输入一个regex并使用页面左侧的
    regex调试器
    。我很好奇哪个regex引擎更优化,以及是否有任何明显的区别特征(除了您提到的行为)-谢谢!我真的不知道。我非常肯定.NET、Perl和JGSoft的引擎非常聪明,但我不知道是否有比较。无论如何,即使是聪明的引擎,在某些情况下也会陷入灾难性的回溯,尽管它们可能会避免一些给“幼稚”实现带来问题的实例。