我的正则表达式需要越来越长的时间来匹配(第5次约30秒),但需要应用大约500轮比赛。 我怀疑是灾难性的回溯。 请帮忙!如何优化此正则表达式:
String regex = "<tr bgcolor=\"ffffff\">\\s*?<td width=\"20%\"><b>((?:.|\\s)+?): *?</b></td>\\s*?<td width=\"80%\">((?:.|\\s)*?)(?=(?:</td>\\s*?</tr>\\s*?<tr bgcolor=\"ffffff\">)|(?:</td>\\s*?</tr>\\s*?</table>\\s*?<b>Tags</b>))";
编辑:因为不清楚(我的不好):我试图获取一个html格式的文档,然后通过提取两个搜索组并在之后添加格式化来重新格式化。
答案 0 :(得分:2)
交替(?:.|\\s)+?
非常低效,因为它涉及太多的回溯。
基本上,此模式的所有变体都非常低效:(?:.|\s)*?
,(?:.|\n)*?
,(?:.|\r\n)*?
以及贪婪的对应物((?:.|\s)*
,(?:.|\n)*
, (?:.|\r\n)*
)。 (.|\s)*?
可能是最糟糕的。
<强>为什么吗
两个备选方案.
和\s
可能匹配同一位置的相同文本,两者至少匹配常规空格。请参阅this demo完成3555步骤,.*?
demo(使用s
修饰符)完成1335步。
Java中的(?:.|\n)*?
/ (?:.|\n)*
等模式经常导致Stack Overflow issue,这里的主要问题与使用与char匹配的交替(已经单独导致回溯)有关char,然后使用未知长度的量词修改组。虽然一些正则表达式引擎可以应对这种并且不会抛出错误,但是这种类型的模式仍然会导致速度减慢并且不建议使用(仅在ElasticSearch Lucene正则表达式引擎中(.|\n)
是匹配任何char的唯一方法)。
<强>解决方案强>
如果要匹配任何字符(包括空格和正则表达式),请使用
进行匹配[\\s\\S]*?
或使用(?s)
(或Pattern.DOTALL
Matcher
选项启用单线模式)并使用.
(例如(?s)start(.*?)end
)。
注意:要操作HTML,请使用专用解析器,例如jsoup。以下是讨论Java HTML parsers的SO帖子。