2012-08-09 120 views
5

我使用正則表達式來從任意長度的輸入字符串中提取鍵 - 值對,並運行到其中,對於一個長的字符串具有重複的圖案,它導致堆棧溢出的情況。爪哇模式導致堆棧溢出

的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.StackOverflowError 
    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 (StackOverflowError 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

回答

3

你的正則表達式看起來過於複雜,比如我想你還沒有完全瞭解字符類是如何工作的。這工作對我好,我不能讓它溢出了:

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