Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/398.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java模式导致堆栈溢出_Java_Regex_Pattern Matching_Stack Overflow_Key Value - Fatal编程技术网

Java模式导致堆栈溢出

Java模式导致堆栈溢出,java,regex,pattern-matching,stack-overflow,key-value,Java,Regex,Pattern Matching,Stack Overflow,Key Value,我使用正则表达式从任意长的输入字符串中提取键值对,并且遇到了这样一种情况:对于具有重复模式的长字符串,它会导致堆栈溢出 KV解析代码如下所示: public static void parse(String input) { String KV_REGEX = "((?:\"[^\"^ ]*\"|[^=,^ ])*) *= *((?:\"[^\"]*\"|[^=,^\\)^ ])*)"; Pattern KV_PATTERN = Pattern.compile(KV_REGEX)

我使用正则表达式从任意长的输入字符串中提取键值对,并且遇到了这样一种情况:对于具有重复模式的长字符串,它会导致堆栈溢出

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}
PID, 5872
version, "7.1.8.x"
build, 1234567
other, done
调用
parse(input2)
生成:

{name, CentOS
family, Linux
category, OS
version, 2.6.x}
PID, 5872
version, "7.1.8.x"
build, 1234567
other, done
这很好(即使第一种情况需要一点字符串处理)。但是,当尝试解析非常长(超过1000个字符长)的类路径字符串时,会发生上述类溢出,但出现以下异常(开始):

字符串太长,无法放在此处,但它具有以下易于复制和重复的结构:

java.class.path=/opt/files/any:/opt/files/any:/opt/files/any:/opt/files/any
任何想要重现问题的人只需在上述字符串中附加几十次
:/opt/files/any
。创建一个包含类路径字符串中大约90个“:/opt/files/any”副本的字符串后,会发生堆栈溢出

是否有一种通用方法可以修改上述
KV_REGEX
字符串,从而不会出现问题并产生相同的结果

我明确地将generic放在上面,而不是(例如)在解析之前检查最大字符串长度的hack

我能想出的最糟糕的解决办法,一个真正的反模式,是

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

有趣的是,它在几次运行中都能起作用。我试过了,但它不够有品位,不能推荐。:-)

您的正则表达式看起来过于复杂,例如,我认为您还不太了解字符类的工作原理。这对我来说更好,我不能再让它溢出了:

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,或任何数量的非
=,)}
字符的内容,祝贺您突破了限制。这部分应该匹配什么?它看起来一点也不正确<代码>[^=,^\\)^]。这是一个很好的例子,向Java爱好者演示了为什么会有人受不了Perl。你早就该把这个发给Jeff Atwood了。这会为他节省一些时间@PNS:这可以简化为
[^=)]
(这会给你一个漂亮的微笑作为奖励)。您的示例也停留在
^
。这看起来确实更好。我会在第一次机会尝试更复杂的案例。谢谢!:-)