2010-04-25 14 views
28

De http://java.sun.com/j2se/1.5.0/docs/api/java/util/regex/Pattern.html:¿Cuál es la diferencia entre z y Z en una expresión regular y cuándo y cómo la uso?

\Z The end of the input but for the final terminator, if any 
\z The end of the input 

Pero ¿qué significa en la práctica? ¿Me puede dar un ejemplo cuando uso ya sea el \ Z o \ z.

En mi prueba pensé que "StackOverflow\n".matches("StackOverflow\\z") devolverá verdadero y "StackOverflow\n".matches("StackOverflow\\Z") devuelve falso. Pero en realidad ambos devuelven falso. ¿Dónde está el error?

Respuesta

22

"Aunque \ Z y $ coinciden solo al final de la cadena (cuando la opción de intercalación y dólar coinciden en los saltos de línea incrustados está desactivada), hay una excepción. Si la cadena termina con una línea break, entonces \ Z y $ coincidirán en la posición anterior a ese salto de línea, en lugar de al final de la cadena. Esta "mejora" fue introducida por Perl, y es copiada por muchos sabores de expresiones regulares, incluidos Java, .NET y PCRE. En Perl, al leer una línea de un archivo, la cadena resultante terminará con un salto de línea. Leer una línea de un archivo con el texto "joe" da como resultado la cadena joe \ n. Cuando se aplica a esta cadena, ambos^[az] + $ y \ A [az] + \ Z coincidirá con joe.

Si solo desea una coincidencia en el extremo absoluto de la cadena, use \ z (minúscula z en su lugar o f mayúscula Z). \ A [a-z] + \ z no coincide con joe \ n. \ Z coincide después de que el salto de línea, que no se corresponde con la clase de caracteres ".

http://www.regular-expressions.info/anchors.html

La forma leí este 'Stackoverflow \ n' .matches ('z Stackoverflow \') debe devolver falso porque su patrón no incluye el salto de línea.

"StackOverflow\n".matches("StackOverflow\\z\\n") => false 
"StackOverflow\n".matches("StackOverflow\\Z\\n") => true 
4

acaba de comprobar él. parece que cuando se invoca Matcher.matches() (como en el código, detrás de las escenas), \ Z se comporta como \ z. sin embargo, cuando se invoca Matcher.find(), se comportan de forma diferente como se esperaba. Lo siguiente devuelve verdadero:

Pattern p = Pattern.compile("StackOverflow\\Z"); 
Matcher m = p.matcher("StackOverflow\n"); 
System.out.println(m.find()); 

y si reemplaza \ Z con \ z, devuelve falso.

Me parece un poco sorprendente ...

+0

No es sorprendente (como acabo entendí de la respuesta aceptada) como '\ z' partidos sólo al final "real" de la cadena. Y su cadena aún no ha terminado después de 'StackOverflow' debido a la nueva línea. – maaartinus

0

Como dijo Eyal, funciona para find(), pero no para los partidos().

Esto realmente tiene sentido. El anclaje \ Z en sí coincide realmente con la posición justo antes del terminador eol final, pero la expresión regular como un todo no concuerda, porque, como un todo, necesita coincidir con el texto completo que se está emparejando, y nada coincide con el terminador. (El \ Z coincide con la posición derecha antes del el terminador, que no es lo mismo.)

Si lo hizo "StackOverflow\n".matches("StackOverflow\\Z.*") debería estar bien.

+0

\ z (z minúscula) no coincide antes de la nueva línea, coincide al final, después de la nueva línea. –

+0

@Jakob: tienes razón. Quise decir \ Z, por supuesto, ese es el que tiene un significado especial. Estaba confundido por la redacción en la pregunta. Corregido ahora. – Avi

+0

\ Z (mayúscula) realmente coincide justo antes de la nueva línea final, tal como lo definen los javadocs. Los documentos de Perl (http://perldoc.perl.org/perlre.html) lo hacen aún más claro: "\ Z \t Coincide solo al final de la cadena, o antes de la nueva línea al final" – Avi

0

Creo que el principal problema aquí es el comportamiento inesperado de matches(): cualquier coincidencia debe consumir toda la cadena de entrada. Sus dos ejemplos fallan porque las expresiones regulares no consumen el avance de línea al final de la cadena. Los anclajes no tienen nada que ver con eso.

En la mayoría de los idiomas, una coincidencia de expresiones regulares puede ocurrir en cualquier lugar, consumiendo todo, algunos o ninguno de los caracteres de entrada. Y Java tiene un método, Matcher#find(), que realiza este tipo de coincidencia tradicional.Sin embargo, los resultados son lo contrario de lo que ha dicho que esperaba:

Pattern.compile("StackOverflow\\z").matcher("StackOverflow\n").find() //false 
Pattern.compile("StackOverflow\\Z").matcher("StackOverflow\n").find() //true 

En el primer ejemplo, los \z debe coincidir con el final de la cadena, pero el avance de línea de arrastre está en el camino. En el segundo, el \Z coincide antes del salto de línea, que está al final de la cadena.

0

\Z coincide con el final de la cadena, al final de la cadena puede seguirse un salto de línea.

enter image description here enter image description here

\z coincide con el final de la cadena, no puede ser seguido por salto de línea.

enter image description here enter image description here

Cuestiones relacionadas