Go 正则表达式中没有灾难性的回溯吗?

Dav*_*asy 4 regex backtracking go

今天在 regex101.com 上测试此正则表达式时, ^([a-z0-9]+(-)*)*([a-z0-9])$ 当我对此字符串进行测试时,出现“灾难性回溯”错误:

带有 PHP 风味:

啊啊啊啊啊啊啊啊啊啊T

带有Python风味:

啊啊啊啊啊啊啊啊啊啊T

使用 ECMAScript 风格,这个较长的字符串超时,“可能是灾难性回溯的迹象”

啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊T

带有字符串的 Java 8 超时

啊啊啊啊啊啊啊啊啊啊啊啊啊啊T

但是,对于更长的此类字符串,Go 没有给出错误或超时事件。相反,它显示no match (0.0ms)

那么,当我的正则表达式在 Go 中使用时,我可以忽略该错误/警告吗?

我也对其原因感兴趣,但以上是我的关键问题。

Dav*_*asy 6

是的,在 Go 中使用正则表达式时,可以安全地忽略灾难性回溯警告。

Go 使用 RE2 算法进行正则表达式,并且 RE2 不使用回溯,因此 Go 中不会出现该问题。 https://en.wikipedia.org/wiki/Regular_expression#Implementations_and_running_times有更多关于正则表达式匹配的替代实现的信息。Go (RE2) 对于输入字符串长度和正则表达式字符串长度具有线性性能:O(mn)。

然而,使用回溯的其他语言/库可能具有指数运行时间,具体取决于正则表达式和输入字符串。regex101.com 显示针对输入字符串运行正则表达式的步骤数,并且您可以看到,当您增加正则表达式的字符串长度(例如 )时,步骤数(a*)*$呈指数增加aaaaaaaaaaaaaaaaX。regex101.com 上的调试器可以一次一步地显示模式匹配执行情况,因此您可以看到回溯如何处理呈指数级增长的替代方案。

@sln提供了我原来的正则表达式的替代方案,消除了指数回溯。将之前/之后的正则表达式简化为aX,对于输入字符串aaaaaaaaaaaaaaaaZ ^(a+X*)*a$需要大约 300,000 个步骤(每个额外的 需要加倍a),但 ^(aX*)*a$需要大约 100 个步骤

我不知道有什么通用方法可以将易受攻击的正则表达式映射到安全的正则表达式 - 除非 @sln 愿意提供服务;-)

原始正则表达式的目的是检查输入字符串是否仅包含 [a-z0-9] 并且-以 [a-z0-9] 开头和结尾。 a, a-b, ab--c, a-b--aa---bbb, ...