正则表达式模式灾难性回溯

Regex Pattern Catastrophic backtracking

我的一个旧 Java 系统中使用了下面显示的正则表达式,该系统最近导致了回溯问题。 回溯线程经常导致机器的 CPU 达到上限,并且在应用程序重新启动之前它不会 return 回溯。

任何人都可以建议一种更好的方法来重写此模式或可以帮助我这样做的工具吗?

模式:

^\[(([\p{N}]*\]\,\[[\p{N}]*)*|[\p{N}]*)\]$

有效值:

[1234567],[89023432],[124534543],[4564362],[1234543],[12234567],[124567],[1234567],[1234567]

灾难性的回溯值——如果值有任何错误(最后添加了一个额外的大括号):

[1234567],[89023432],[124534543],[4564362],[1234543],[12234567],[124567],[1234567],[1234567]]

+ 是您的意思时,切勿使用 *。关于您的正则表达式,我注意到的第一件事是几乎所有内容都是可选的。只需要左方括号和右方括号,我敢肯定您不想将 [] 视为有效输入。

失控回溯的最大原因之一是有两个或多个可以匹配相同事物的备选方案。这就是 |[\p{N}]* 部分的内容。正则表达式引擎必须在放弃之前尝试通过字符串的每条可能的路径,因此所有这些 \p{N}* 结构都会对每组数字进行无休止的拔河 war。

但是试图解决这些问题是没有意义的,因为整体结构是错误的。我想这就是您要找的:

^\[\p{N}+\](?:,\[\p{N}+\])*$

在它消耗完第一个标记([1234567])后,如果字符串中的下一个不是逗号或字符串的结尾,它会立即失败。如果它 看到一个逗号,它必须继续匹配另一个完整的标记 ([89023432]),否则它会立即失败。

这可能是您在创建正则表达式时要记住的最重要的事情:如果它会失败,您希望它尽快失败。您可以使用原子组和所有格量词等功能来达到此目的,但如果您正确地使用了正则表达式的结构,则很少需要它们。回溯不是必然的。