这个正则表达式不应该发生灾难性的回溯

时间:2011-09-11 13:46:52

标签: java regex backtracking

有人可以解释为什么Java的正则表达式引擎会在这个正则表达式上进入灾难性的回溯模式吗?根据我的判断,每次交替都与其他所有交替相互排斥。

^(?:[^'\"\\s~:/@#\\|\\^\\&\\[\\]\\(\\)\\\\\\{\\}][^\"\\s~:/@#\\|\\^\\&\\[\\]\\(\\)\\\\\\{\\}]*|
\"(?:[^\"]+|\"\")+\"|
'(?:[^']+|'')+')

文字:'pão de açúcar itaucard mastercard platinum SUSTENTABILIDADE])

为某些替换添加占有匹配修复了问题,但我不知道为什么 - Java的正则表达式lib必须非常错误才能在互斥分支上回溯。

 ^(?:[^'\"\\s~:/@#\\|\\^\\&\\[\\]\\(\\)\\\\\\{\\}][^\"\\s~:/@#\\|\\^\\&\\[\\]\\(\\)\\\\\\{\\}]*|
 \"(?:[^\"]++|\"\")++\"|
 '(?:[^']++|'')++')

3 个答案:

答案 0 :(得分:17)

答案 1 :(得分:6)

我不得不承认这也让我感到惊讶,但我在RegexBuddy中获得了相同的结果:它在经过一百万步之后就退出了。我知道关于灾难性回溯的警告倾向于关注嵌套量词,但根据我的经验,交替至少是危险的。事实上,如果我改变你的正则表达式的最后一部分:

'(?:[^']+|'')+'

......对此:

'(?:[^']*(?:''[^']*)*)'

......它只用了十一步就失败了。这是Friedl的“展开循环”技术的一个例子,他将这种技术分解为:

opening normal * ( special normal * ) * closing
   '     [^']        ''     [^']           '

嵌套星星是安全的,只要:

  1. specialnormal永远不会匹配相同的内容,
  2. special始终匹配至少一个字符,
  3. special是原子的(必须只有一种方法可以匹配)。
  4. 然后正则表达式将失败以匹配最小的回溯,并且成功而根本没有回溯。另一方面,交替版本几乎可以保证回溯,并且在不可能匹配的情况下,随着目标字符串的长度增加,它会快速失控。如果它没有在某些风格中过度回溯,那是因为它们具有专门针对这个问题的内置优化 - 到目前为止很少有风味的东西。

答案 2 :(得分:0)

  

有人可以解释为什么java的正则表达式引擎会在这个正则表达式上进入灾难性模式吗?

对于字符串:

'pão de açúcar itaucard mastercard platinum SUSTENTABILIDADE])

似乎这部分正则表达式会出现问题:

'(?:[^']+|'')+'

匹配第一个',然后无法匹配结束',从而回溯所有嵌套量词的组合。

如果允许正则表达式回溯,它将回溯(失败时)。使用原子组和/或占有量词来防止这种情况发生。


是的,你不需要那个正则表达式中的大多数逃脱。你(可能)需要在角色类([])中逃脱的是chars ^-]。但通常你可以定位它们,这样它们也不需要转义。当然\和你要求的字符串仍然需要(双)转义。

"^(?:[^]['\"\\s~:/@#|^&(){}\\\\][^][\"\s~:/@#|^&(){}\\\\]*|\"(?:[^\"]++|\"\")++\"|'(?:[^']++|'')++')"