爪哇模式导致堆栈溢出

问题描述:

我使用正则表达式来从任意长度的输入字符串中提取键 - 值对,并运行到其中,对于一个长的字符串具有重复的图案,它导致堆栈溢出的情况。爪哇模式导致堆栈溢出

的KV-解析代码看起来是这样的:

public static void parse(String input) 
{ 
    String KV_REGEX = "((?:\"[^\"^ ]*\"|[^=,^ ])*) *= *((?:\"[^\"]*\"|[^=,^\\)^ ])*)"; 
    Pattern KV_PATTERN = Pattern.compile(KV_REGEX); 

    Matcher matcher = KV_PATTERN.matcher(input); 

    System.out.println("\nMatcher groups discovered:"); 

    while (matcher.find()) 
    { 
     System.out.println(matcher.group(1) + ", " + matcher.group(2)); 
    } 
} 

输出的一些虚构的例子:

String input1 = "2012-08-09 09:10:25,521 INFO com.a.package.SomeClass - Everything working fine {name=CentOS, family=Linux, category=OS, version=2.6.x}"; 
    String input2 = "2012-08-09 blah blah 09:12:38,462 Log for the main thread, PID=5872, version=\"7.1.8.x\", build=1234567, other=done"; 

调用parse(input1)生产:

{name, CentOS 
family, Linux 
category, OS 
version, 2.6.x} 

调用parse(input2)生产:

PID, 5872 
version, "7.1.8.x" 
build, 1234567 
other, done 

这是优良(即使是使用用于第一壳体所需要的比特串的处理)。但是,试图解析很长(超过1000个字符)的类路径字符串,上述类溢出,但以下情况除外时(启动):

Exception in thread "main" java.lang.*Error 
    at java.util.regex.Pattern$BitClass.isSatisfiedBy(Pattern.java:2927) 
    at java.util.regex.Pattern$8.isSatisfiedBy(Pattern.java:4783) 
    at java.util.regex.Pattern$8.isSatisfiedBy(Pattern.java:4783) 
    at java.util.regex.Pattern$8.isSatisfiedBy(Pattern.java:4783) 
    at java.util.regex.Pattern$8.isSatisfiedBy(Pattern.java:4783) 
    at java.util.regex.Pattern$CharProperty.match(Pattern.java:3345) 
    ... 

字符串太长,放在这里,但它具有以下,容易复制和重复结构:

java.class.path=/opt/files/any:/opt/files/any:/opt/files/any:/opt/files/any 

谁想要重现该问题只需要几十次追加:/opt/files/any上面的字符串。在创建一个包含约90个“:/ opt/files/any”副本的字符串后,会发生堆栈溢出。

有没有一种通用的方法,上述KV_REGEX字符串可以修改,这样就不会出现问题,同样的结果产生?

我明确提出通用的上面,而不是黑客的是(例如)在解析之前检查的最大字符串长度。

最总值(GDP)修正我能想出,一个真正的反模式,是

public void safeParse(String input) 
{ 
    try 
    { 
     parse(input); 
    } 
    catch (*Error e) // Or even Throwable! 
    { 
     parse(input.substring(0, MAX_LENGTH)); 
    } 
} 

有趣的是,它工作在几个运行我尝试过,但它是不是足够有品位的建议。 :-)

+2

祝贺您打破了限制。 – kosa 2012-08-09 20:32:52

+0

谢谢!我会随时接受奖励的解决方案! :-)究竟是什么限制破了? – PNS 2012-08-09 20:36:33

+1

这部分应该匹配什么?它看起来不正确。 '[^ =,^ \\)^]'。 – Keppil 2012-08-09 20:36:50

你的正则表达式看起来过于复杂,比如我想你还没有完全了解字符类是如何工作的。这工作对我好,我不能让它溢出了:

public static void parse(String input) { 
    String KV_REGEX = "(\"[^\" ]*\"|[^{=, ]*) *= *(\"[^\"]*\"|[^=,) }]*)"; 
    Pattern KV_PATTERN = Pattern.compile(KV_REGEX); 

    Matcher matcher = KV_PATTERN.matcher(input); 

    System.out.println("\nMatcher groups discovered:"); 

    while (matcher.find()) { 
     System.out.println(matcher.group(1) + ", " + matcher.group(2)); 
    } 
} 

要打破正则表达式,这将匹配:

(\"[^\" ]*\"|[^{=, ]*):任何附带" S,或任意数量的非{=,字符

*= *:零到任意数目的空格,其次=,后面的零到任意数目的空格

(\"[^\"]*\"|[^=,) }]*):任何与" s或任意数量的非=,) }字符对应的内容

+0

这确实看起来更好。我会尝试用我的更复杂的案例一次机会。谢谢! :-) – PNS 2012-08-09 21:07:05