2011-12-29 20 views
6

Duplicar posibles:
Java regex anomaly?no se puede entender el comportamiento String.replaceAll no expansivo

idea de por qué la siguiente prueba falla (devuelve "xx" en lugar de "x")

@Test 
public void testReplaceAll(){ 
    assertEquals("x", "xyz".replaceAll(".*", "x")); 
} 

no quiero hacer "^.*$" .... Quiero entender este comportamiento. alguna pista?

+0

¿Qué significa '" xyz ".replaceAll (". * "," X ")' return? – robert

+0

@robert Devuelve '" xx "'. –

+0

@JackEdmonds ¿Por qué '" xx "' y no '" xxx "'? – user219882

Respuesta

9

Sí, es exactamente lo mismo que se describe en this question!

.* será el primer partido toda la entrada, pero entonces también una cadena vacía al final de la entrada ...

Vamos a simbolizar el motor de expresiones regulares con | y la entrada con <...> en su ejemplo.

  • input: <xyz>;
  • motor regex, antes de la primera ejecución: <|xyz>;
  • motor regex, después de la primera ejecución: <xyz|> (texto coincidente: "xyz");
  • motor regex, después de la segunda ejecución: <xyz>| (texto combinado: "").

No todos los motores regex se comportan de esta manera. Java lo hace, sin embargo. También lo hace Perl. Sed, como contraejemplo, posicionará su cursor después del final de la entrada en el paso 3.

Ahora, también tiene que entender una cosa crucial: los motores regex, cuando encuentran una coincidencia de longitud cero, siempre avanzan uno personaje. De lo contrario, considere lo que sucedería si intentara reemplazar '^' con 'a': '^' coincide con una posición, por lo tanto, es una coincidencia de longitud cero. Si el motor no avanzaba un carácter, "x" sería reemplazado por "ax", que sería reemplazado por "aax", etc. Por lo tanto, después de la segunda coincidencia, que está vacía, el motor de expresiones regulares de Java avanza un "carácter" "... De los cuales no hay ninguno: final del procesamiento.

+0

, pero ¿no se supone que debe ser codicioso? – ekeren

+0

Bueno, es codicioso, ¿verdad? Recuerde que el '*' significa "** ZERO ** o más". Entonces, '. *' Está perfectamente satisfecho con una cadena vacía. – fge

+0

Después de la edición, comprendo: java repite los hallazgos ... y cuando alcanza el último carácter, también provoca el emparejamiento (el emparejamiento vacío ...) ¡Gracias! – ekeren

0
@Test 
public void testReplaceAll(){ 
    assertEquals("x", "xyz".replaceAll(".+", "x")); 
} 

probablemente haría el truco, ya que requiere una o más caracteres y así impide la conducta en la que * podría coincidir con cero caracteres y sustituirla por "x".

Cuestiones relacionadas