如何从正则表达式中消除灾难性的回溯

时间:2018-10-21 14:37:33

标签: regex

我开发了以下正则表达式来解析一些赛车数据:

^(\w+\s?\w+)-?(\w+\s?\w+)?-?(\w+\s?\w+)?\s(\(.*?\))-?(\w+\s?\w+)-?(\w+\s?\w+\s?\w+)?-?(\w+\s?\w+\s?\w+)?\s(\(.*?\))-?(\w+\s?\w+\s?\w+)-?(\w+\s?\w+\s?\w+)?-?(\w+\s?\w+\s?\w+\s?\w+)?\s(\(.*?\))-?(\w+\s?\w+\s?\w+)-?\s(\(.*?\))-?

正则表达式可以很好地处理我的大部分数据(请参见示例)This works great

但是对于某些文本数据,我遇到了灾难性的回溯错误,我无法弄清原因。 (请参见示例)This fails

我可以在正则表达式中进行一些更改,以免出现错误。还有,导致失败的失败字符串是什么?

1 个答案:

答案 0 :(得分:2)

明显的红色标志:您的正则表达式包含.*?,这始终是一个坏主意(太不受限制)。它还包含\w+\s?\w+-?\w+等,(因为定界符都是可选的)可以与\w+\w+\w+等进行匹配,这可能会导致灾难性的回溯,因为所有\w+匹配都可能重叠。

也就是说,像foobar这样的字符串可以被\w+\w+\w+匹配为foob a rf o obarfo ob ar或两者之间的任何内容。所有这些在道德上都是等效的(正则表达式匹配覆盖了相同的子字符串),但是如果正则表达式的后面部分导致匹配失败,则正则表达式引擎将循环通过所有可能的方式在{之间分隔foobar {1}},然后放弃并返回失败。

解决方案是确保正则表达式的子部分永远不会重叠。

例如,要匹配一个或两个用空格分隔的单词,应使用\w+\w+\w+,而不是\w+(?:\s\w+)?