Sto usando un'espressione regolare per estrarre le coppie chiave-valore da stringhe di input arbitrariamente lunghe e sono state eseguite in un caso in cui, per una stringa lunga con pattern ripetitivi, provoca uno stack overflow.Java Pattern causa overflow dello stack
Il codice KV-analisi sembra qualcosa di simile:
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));
}
}
Alcuni esempi fittizi di uscita:
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";
Calling parse(input1)
produce:
{name, CentOS
family, Linux
category, OS
version, 2.6.x}
Calling parse(input2)
produce:
PID, 5872
version, "7.1.8.x"
build, 1234567
other, done
Questo va bene (anche con un po 'di elaborazione di stringhe richiesta per il primo caso). Tuttavia, quando si cerca di analizzare un tempo molto lungo (lunga più di 1000 caratteri) stringa di percorso di classe, si verifica il suddetto troppo pieno di classe, con la seguente eccezione (inizio):
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)
...
La stringa è troppo lungo per mettere qui, ma ha la seguente struttura, facilmente riproducibile e ripetitivo:
java.class.path=/opt/files/any:/opt/files/any:/opt/files/any:/opt/files/any
Chiunque voglia riprodurre il problema ha solo bisogno di aggiungere :/opt/files/any
qualche decina di volte alla stringa sopra. Dopo aver creato una stringa con circa 90 copie di ":/opt/files/any" presenti nella stringa classpath, si verifica l'overflow dello stack.
Esiste un modo generico per modificare la stringa KV_REGEX
, in modo che il problema non si verifichi e vengano prodotti gli stessi risultati?
Ho inserito esplicitamente il metodo sopra, al contrario degli hack che (ad esempio) controllano la lunghezza massima della stringa prima dell'analisi.
La correzione più lordo potevo venire con, un vero e proprio anti-modello, è
public void safeParse(String input)
{
try
{
parse(input);
}
catch (StackOverflowError e) // Or even Throwable!
{
parse(input.substring(0, MAX_LENGTH));
}
}
Stranamente, funziona in un paio di basi ho provato, ma non è qualcosa di abbastanza piacevole, sia per consigliare . :-)
Congratulazioni per aver superato i limiti. – kosa
Grazie! Accetterei una soluzione per un premio in qualsiasi momento! :-) Cos'era esattamente il limite rotto? – PNS
A cosa dovrebbe corrispondere questa parte? Non sembra affatto corretto. '[^ =,^\\) ^]'. – Keppil