2012-08-09 11 views
5

正規表現を使用して任意の長い入力文字列からキーと値のペアを抽出し、繰り返しパターンの長い文字列に対してスタックオーバーフローが発生するケースを実行しています。出力のJavaパターンでスタックオーバーフローが発生する

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)を呼び出し生成:

はKV-解析するコードは次のようになります

これは問題ありません(最初のケースでは少しの文字列処理が必要です)。文字列がここに置くためには長すぎる

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) 
    ... 

を、それ以下の例外を除いて、前述のクラスのオーバーフローが発生し、非常に長い(1,000文字)クラスパス文字列を解析しようとしたときただし、(スタート)以下、簡単に再現可能と繰り返し構造を有する:問題を再現したい

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

誰もがちょうど上記の文字列に:/opt/files/any数十回を追加する必要があります。クラスパス文字列に ":/ opt/files/any"が約90個コピーされた文字列を作成すると、スタックオーバーフローが発生します。

上記のKV_REGEX文字列を変更できるという一般的な方法があるため、問題は発生せず、同じ結果が生成されますか?

パーズする前に最大の文字列の長さをチェックする(たとえば)ハックとは対照的に、上記のジェネリックを明示的に指定します。

私が思い付くことができる最も総修正、真のアンチパターンは、Funnily十分

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

あり、それは私がそれを試してみましたいくつかの実行で動作しますが、それはお勧めするのに十分な味わい深いものではありません。 :-)

+2

制限を破りましたことをお祝いします。 – kosa

+0

ありがとう!私はいつでも報酬のための解決策を受け入れるだろう! :-)限界が壊れていたのは何ですか? – PNS

+1

この部分は何と一致するはずですか?それはまったく正しいとは思わない。 '[^ =、^ \\)^]'。 – Keppil

答えて

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)); 
    } 
} 

は、正規表現を打破するために、これは一致します:

(\"[^\" ]*\"|[^{=, ]*):何が"秒、または非任意の数で囲まれました{=,文字

*= *:スペースの任意の数のゼロに続くゼロ=続く任意の数のスペースに、

(\"[^\"]*\"|[^=,) }]*)"または任意の数の非=,) }文字で囲まれたもの

+0

これは本当に良く見えます。もっと複雑なケースの最初のチャンスで試してみます。ありがとう! :-) – PNS

関連する問題