我开发了以下正则表达式来解析一些赛车数据:
^(\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
我可以在正则表达式中进行一些更改,以免出现错误。还有,导致失败的失败字符串是什么?
答案 0 :(得分:2)
明显的红色标志:您的正则表达式包含.*?
,这始终是一个坏主意(太不受限制)。它还包含\w+\s?\w+-?\w+
等,(因为定界符都是可选的)可以与\w+\w+\w+
等进行匹配,这可能会导致灾难性的回溯,因为所有\w+
匹配都可能重叠。
也就是说,像foobar
这样的字符串可以被\w+\w+\w+
匹配为foob
a
r
或f
o
obar
或fo
ob
ar
或两者之间的任何内容。所有这些在道德上都是等效的(正则表达式匹配覆盖了相同的子字符串),但是如果正则表达式的后面部分导致匹配失败,则正则表达式引擎将循环通过所有可能的方式在{之间分隔foobar
{1}},然后放弃并返回失败。
解决方案是确保正则表达式的子部分永远不会重叠。
例如,要匹配一个或两个用空格分隔的单词,应使用\w+\w+\w+
,而不是\w+(?:\s\w+)?
。