【问题标题】:Why do /\w+:/ and /\S+:/ handle backtracking differently?为什么 /\w+:/ 和 /\S+:/ 处理回溯的方式不同?
【发布时间】:2016-02-15 19:55:04
【问题描述】:

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

【问题讨论】:

  • 我真的很好奇你是如何一步一步做到这一点的,所以你可以分析一下!
  • @Mehrdad:在 regex101.com 上,输入正则表达式并使用页面左侧的 regex debugger

标签: regex pcre backtracking


【解决方案1】:

这是一个名为 auto-possessification 优化。

来自http://pcre.org/pcre.txt

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

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

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

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


PCRETEST

您可以使用pcretest查看差异(有一个Windows版本您可以下载here)。

/\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)(禁用此优化),则模式 /(*NO_AUTO_POSSESS)\w+:/ 需要 14 步并输出:

/(*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 不支持这个动词。

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

  1. /\S+:/(14 步)-https://regex101.com/r/cw7hGh/1/debugger

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

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

regex101 调试器:

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

    • 我很好奇哪些正则表达式引擎更优化,以及是否有任何明显的区别特征(除了你提到的行为) - 谢谢!
    • 我真的不知道。我很确定 .NET、Perl 和 JGSoft 的引擎非常聪明,但我不知道是否可以进行比较。
    • 无论如何,即使是聪明的引擎,在某些情况下也会陷入灾难性的回溯,尽管它们可能会避免一些给“幼稚”实现带来问题的情况。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-06-02
    • 1970-01-01
    • 1970-01-01
    • 2020-03-11
    • 1970-01-01
    • 1970-01-01
    • 2017-07-22
    相关资源
    最近更新 更多