2010-09-10 17 views
6

Estoy tratando de usar una expresión regular con el escáner para que coincida con una cadena de un archivo. La expresión regular funciona con todos los contenidos del archivo excepto por esta línea:Mi regex está causando un desbordamiento de pila en Java; ¿Qué me estoy perdiendo?

DNA="ITTTAITATIATYAAAYIYI[....]ITYTYITTIYAIAIYIT" 

en el archivo real, la elipsis representa varios miles de caracteres.

Cuando el bucle que lee el archivo llega a la línea que contiene las bases, se produce un error de desbordamiento de pila.

Aquí es el bucle:

while (scanFile.hasNextLine()) { 
    final String currentLine = scanFile.findInLine(".*"); 
    System.out.println("trying to match '" + currentLine + "'"); 
    Scanner internalScanner = new Scanner(currentLine); 
    String matchResult = internalScanner.findInLine(Constants.ANIMAL_INFO_REGEX); 
    assert matchResult != null : "there's no reason not to find a match"; 
    matches.put(internalScanner.match().group(1), internalScanner.match().group(2)); 
    scanFile.nextLine(); 
    } 

y la expresión regular:

static final String ANIMAL_INFO_REGEX = "([a-zA-Z]+) *= *\"(([a-zA-Z_.]| |\\.)+)"; 

Aquí es la traza fracaso:

java.lang.StackOverflowError 
    at java.util.regex.Pattern$CharProperty.match(Pattern.java:3360) 
    at java.util.regex.Pattern$Branch.match(Pattern.java:4131) 
    at java.util.regex.Pattern$GroupHead.match(Pattern.java:4185) 
    at java.util.regex.Pattern$Loop.match(Pattern.java:4312) 
    at java.util.regex.Pattern$GroupTail.match(Pattern.java:4244) 
    at java.util.regex.Pattern$BranchConn.match(Pattern.java:4095) 
    at java.util.regex.Pattern$CharProperty.match(Pattern.java:3362) 
    at java.util.regex.Pattern$Branch.match(Pattern.java:4131) 
    at java.util.regex.Pattern$GroupHead.match(Pattern.java:4185) 
    at java.util.regex.Pattern$Loop.match(Pattern.java:4312) 
    at java.util.regex.Pattern$GroupTail.match(Pattern.java:4244) 
    at java.util.regex.Pattern$BranchConn.match(Pattern.java:4095) 
    at java.util.regex.Pattern$CharProperty.match(Pattern.java:3362) 
    at java.util.regex.Pattern$Branch.match(Pattern.java:4131) 
    at java.util.regex.Pattern$GroupHead.match(Pattern.java:4185) 
    at java.util.regex.Pattern$Loop.match(Pattern.java:4312) 
    at java.util.regex.Pattern$GroupTail.match(Pattern.java:4244) 
    at java.util.regex.Pattern$BranchConn.match(Pattern.java:4095) 
    ...etc (it's all regex). 

Gracias tanto!

+0

puedo ver que hace que se obtiene una StackOverflow ...: P ~ –

Respuesta

3

Pruebe esta versión simplificada de su expresión regular que elimina algunos operadores | innecesarios (que podrían haber estado causando que el motor de expresiones regulares haga muchas ramificaciones) e incluye los anclajes de inicio y fin de línea.

static final String ANIMAL_INFO_REGEX = "^([a-zA-Z]+) *= *\"([a-zA-Z_. ]+)\"$"; 
4

Esto se parece a bug 5050507. Estoy de acuerdo con Asaph en que eliminar la alternancia debería ayudar; el error dice específicamente "Evita la alternancia siempre que sea posible". Creo que se puede ir probablemente aún más simple:

"^([a-zA-Z]+) *= *\"([^\"]+)" 
+1

1, pero quiero hacer hincapié en que el insecto ** ** informe es falso Las observaciones en la evaluación se aplican a * cualquier * motor regex dirigido por regex (o NFA), no solo a Java. (Eso incluye Perl, Python, PHP, .NET, JavaScript y muchos otros). –

1

Como los otros han dicho, su expresión regular es mucho menos eficiente de lo que debería ser. Me gustaría tener un paso más allá y el uso de cuantificadores posesivos:

"^([a-zA-Z]++) *+= *+\"([^\"]++)\"$" 

Pero la forma en que está utilizando el escáner no tiene mucho sentido, tampoco. No es necesario usar findInLine(".*") para leer la línea; eso es lo que hace nextLine(). Y no necesita crear otro escáner para aplicar su expresión regular; solo usa un Matcher.

static final Pattern ANIMAL_INFO_PATTERN = 
    Pattern.compile("^([a-zA-Z]++) *+= *+\"([^\"]++)\"$"); 

...

Matcher lineMatcher = ANIMAL_INFO_PATTERN.matcher(""); 
    while (scanFile.hasNextLine()) { 
    String currentLine = scanFile.nextLine(); 
    if (lineMatcher.reset(currentLine).matches()) { 
     matches.put(lineMatcher.group(1), lineMatcher.group(2)); 
    } 
    } 
Cuestiones relacionadas