2010-04-29 10 views
10

¿Se pueden usar las referencias en un lookbehind?Backreferences en lookbehind

Digamos que quiero split donde esté detrás de mí, un personaje se repite dos veces.

String REGEX1 = "(?<=(.)\\1)"; // DOESN'T WORK! 
    String REGEX2 = "(?<=(?=(.)\\1)..)"; // WORKS! 

    System.out.println(java.util.Arrays.toString(
     "Bazooka killed the poor aardvark (yummy!)" 
     .split(REGEX2) 
    )); // prints "[Bazoo, ka kill, ed the poo, r aa, rdvark (yumm, y!)]" 

Usando REGEX2 (donde la referencia inversa se encuentra en una búsqueda hacia delante anidado dentro de una búsqueda hacia atrás) funciona, pero REGEX1 da este error en tiempo de ejecución:

Look-behind group does not have an obvious maximum length near index 8 
(?<=(.)\1) 
     ^

Este tipo de tiene sentido, me supongamos, porque en general la referencia inversa puede capturar una cadena de cualquier longitud (si el compilador de expresiones regulares es un poco más inteligente, podría determinar que \1 es (.) en este caso, y por lo tanto tiene una longitud finita).

Entonces, ¿hay alguna manera de utilizar una referencia inversa en un lookbehind?

Y si no lo hay, ¿siempre se puede evitar usar esta búsqueda anidada? ¿Hay otras técnicas comúnmente usadas?

+1

Interesante y +1 por su ingeniosa solución. No uso Java, por lo que no puedo probarlo, ¿qué sucede si el grupo referenciado está fuera de la apariencia, como '(? <= \\ 1) (.)'? –

+0

@Tim: resulta esencialmente el mismo 'PatternSyntaxException'. Por cierto, si alguien quiere jugar con una variante de este problema, acabo de escribir uno en codingBat: http://codingbat.com/prob/p266235 – polygenelubricants

+0

@polygenelubricants Desearía poder votar mejor esta expresión regular: (? <= (? = (.) \\ 1) ..) por lo menos 10 veces. ¡muy elegante! – Eugene

Respuesta

5

Parece que sospecha que las referencias hacia atrás no se pueden usar en Java lookbehinds. La solución que propusiste hace que la longitud finita del lookbehind sea explícita y me parece muy inteligente.

Estaba intrigado por saber qué hace Python con esta expresión regular. Python solo admite look-behind de longitud fija, no de longitud definida como Java, pero esta expresión regular es de longitud fija. No podía usar directamente porque re.split() pitón de re.split() nunca se divide en un partido de vacío, pero creo que he encontrado un error en re.sub():

>>> r=re.compile("(?<=(.)\\1)") 
>>> a=re.sub(r,"|", "Bazooka killed the poor aardvark (yummy!)") 
>>> a 
'Bazo|oka kil|led the po|or a|ardvark (yum|my!)' 

La búsqueda hacia atrás coincide entre los dos personajes duplicados!

+0

Consulte http://stackoverflow.com/questions/2628534/codingbat-plusout-using-regex para obtener más diversión con expresiones regulares. – polygenelubricants

+0

Es estúpido que 're.split()' no se divida en una coincidencia vacía, sin embargo. ¿Por qué demonios lo harían así? Creo que hay muchas veces que quieres dividir simplemente en base a aserciones en lugar de un delimitador real no vacío. – polygenelubricants

+0

He pedido lo mismo en el rastreador de errores de Python. Probablemente no fue intencionado, pero se lo deja solo para que no cause problemas de compatibilidad; hay una revisión importante del motor regex en curso, pero puede pasar un tiempo hasta que el nuevo módulo regex se fusione en la biblioteca estándar. –

Cuestiones relacionadas