Estoy usando una expresión regular para extraer pares clave-valor de cadenas de entrada arbitrariamente largas y me he encontrado con un caso en el que, para una cadena larga con patrones repetitivos, causa un desbordamiento de pila.El patrón Java causa desbordamiento de pila
El código KV-análisis se ve algo como esto:
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));
}
}
Algunos ejemplos ficticios de salida:
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
Esto está bien (incluso con un poco de procesamiento de cadena requerido para el primer caso). Sin embargo, cuando se trata de analizar un muy largo (más de 1.000 caracteres) cadena de ruta de clases, se produce el desbordamiento de la clase antes mencionada, con la siguiente excepción (inicio):
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 cadena es demasiado larga para poner aquí, pero tiene la siguiente estructura, fácilmente reproducible y repetitivo:
java.class.path=/opt/files/any:/opt/files/any:/opt/files/any:/opt/files/any
Cualquier persona que quiera reproducir el problema sólo tiene que añadir :/opt/files/any
unas pocas docenas de veces a la cadena anterior. Después de crear una cadena con aproximadamente 90 copias de ":/opt/files/any" presente en la cadena classpath, se produce el desbordamiento de la pila.
¿Existe una forma genérica de que la cadena KV_REGEX
anterior se pueda modificar para que el problema no se produzca y se obtengan los mismos resultados?
Puse explícitamente encima de genérico, a diferencia de los piratas informáticos que (por ejemplo) comprueban para una longitud de cadena máxima antes de analizar.
La revisión más bruto que podía llegar a, un verdadero anti-patrón, es
public void safeParse(String input)
{
try
{
parse(input);
}
catch (StackOverflowError e) // Or even Throwable!
{
parse(input.substring(0, MAX_LENGTH));
}
}
Curiosamente, funciona en algunas carreras que lo probé, pero no es algo lo suficientemente buen gusto para recomendar . :-)
Felicitaciones por haber superado los límites. – kosa
¡Gracias! ¡Aceptaría una solución para una recompensa en cualquier momento! :-) ¿Cuál fue exactamente el límite roto? – PNS
¿Qué se supone que esta parte coincide? No parece correcto en absoluto. '[^ =,^\\) ^]'. – Keppil