sun jdk 6.0.24中的java.util.regex中的错误?

时间:2011-05-17 15:14:34

标签: java regex

以下代码阻止我的系统。为什么呢?

System.out.println( Pattern.compile( 
   "^((?:[^'\"][^'\"]*|\"[^\"]*\"|'[^']*')*)/\\*.*?\\*/(.*)$", 
   Pattern.MULTILINE | Pattern.DOTALL ).matcher( 
   "\n\n\n\n\n\nUPDATE \"$SCHEMA\" SET \"VERSION\" = 12 WHERE NAME = 'SOMENAMEVALUE';"
   ).matches() );

模式(用于检测/*...*/形式但不在'"内)的评论应该很快,因为它是确定性的...... 为什么需要太长时间?

4 个答案:

答案 0 :(得分:8)

你遇到了catastrophic backtracking

查看正则表达式,很容易看出.*?(.*)如何匹配相同的内容,因为两者也可以匹配介入的\*/部分(点匹配全部,请记住)。加上(甚至更有问题),它们也可以匹配((?:[^'"][^'"]*|"[^"]*"|'[^']*')*)匹配的相同内容。

正在尝试所有排列时,正则表达式引擎陷入困境,特别是如果您正在测试的字符串很长。

我刚刚在RegexBuddy中检查了你的正则字符串。它在正则表达式引擎的1.000.000步之后中止匹配尝试。 Java将继续搅拌,直到它通过所有排列或直到发生堆栈溢出...

您可以通过禁止回溯已经匹配的内容来极大地提高正则表达式的性能。您可以使用atomic groups,将正则表达式更改为

^((?>[^'"]+|"[^"]*"|'[^']*')*)(?>/\*.*?\*/)(.*)$

或者,作为Java字符串:

"^((?>[^'\"]+|\"[^\"]*\"|'[^']*')*)(?>/\\*.*?\\*/)(.*)$"

这减少了正则表达式引擎必须经历的步数> gt; 100万到58岁。

请注意,这只会发现第一次出现评论,因此您必须重复应用正则表达式,直到它失败。

编辑:我刚添加了两个对表达起作用很重要的斜杠。但我不得不改变超过6个字符.... :(

答案 1 :(得分:1)

答案 2 :(得分:0)

我认为这是因为这一点:

(?:[^'\"][^'\"]*|\"[^\"]*\"|'[^']*')*

删除第二个和第三个备选方案可以:

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

或:

(?:[^'\"]+)*

重复重复可能需要很长时间。

答案 3 :(得分:0)

对于评论/**/检测,我建议您使用以下代码:

String str = "\n\n\n\n\n\nUPDATE \"$SCHEMA\" /*a comment\n\n*/ SET \"VERSION\" = 12 WHERE NAME = 'SOMENAMEVALUE';";
Pattern pt = Pattern.compile("\"[^\"]*\"|'[^']*'|(/\\*.*?\\*/)", 
                             Pattern.MULTILINE | Pattern.DOTALL);
Matcher matcher = pt.matcher(str);
boolean found = false;
while (matcher.find()) {
   if (matcher.group(1) != null) {
      found = true;
      break;
   }
}
if (found)
   System.out.println("Found Comment: [" + matcher.group(1) + ']');
else
   System.out.println("Didn't find Comment");

对于上面的字符串,它会打印:

Found Comment: [/*a comment

*/]

但如果我输入字符串更改为:

String str = "\n\n\n\n\n\nUPDATE \"$SCHEMA\" '/*a comment\n\n*/' SET \"VERSION\" = 12 WHERE NAME = 'SOMENAMEVALUE';";

OR

String str = "\n\n\n\n\n\nUPDATE \"$SCHEMA\" \"/*a comment\n\n*/\" SET \"VERSION\" = 12 WHERE NAME = 'SOMENAMEVALUE';";

输出是:

Didn't find Comment