regulares regular rango probar palabra numeros expresiones expresion exacta especiales espacio consecutivos caracteres blanco alfanumerico java regex string escaping charsequence

rango - expresiones regulares java pdf



¿Por qué String.replaceAll() en java requiere 4 barras "////" en la expresión regular para reemplazar realmente "/"? (6)

Esto se debe a que Java intenta darle un significado especial a la cadena de reemplazo, por lo que / $ será un signo $ literal, pero en el proceso parece que han eliminado el significado especial real de /

Mientras text.replaceAll("////","/") , al menos se puede considerar que está bien en algún sentido (aunque en sí mismo no es del todo correcto), todas las tres ejecuciones, text.replaceAll("/n","/") , text.replaceAll("//n","/") , text.replaceAll("///n","/") dando el mismo resultado parece aún más divertido. Simplemente es contradictorio sobre por qué han restringido el funcionamiento del text.replaceAll("//","/") por el mismo motivo.

Java no se equivocó con expresiones regulares. Es porque a Java le gusta jugar con codificadores tratando de hacer algo único y diferente, cuando no es necesario.

Recientemente me di cuenta de que String.replaceAll (regex, reemplazo) se comporta de manera muy extraña cuando se trata del carácter de escape "/" (barra inclinada)

Por ejemplo, considere que hay una cadena con filepath - String text = "E://dummypath" y queremos reemplazar "//" por "/" .

text.replace("//","/") da el resultado "E:/dummypath" mientras que text.replaceAll("//","/") genera la excepción java.util.regex.PatternSyntaxException .

Si queremos implementar la misma funcionalidad con replaceAll() necesitamos escribirla como, text.replaceAll("////","/")

Una diferencia notable es replaceAll() tiene sus argumentos como reg-ex mientras que replace() tiene argumentos character-sequence!

Pero text.replaceAll("/n","/") funciona exactamente de la misma manera que su secuencia de caracteres equivalente text.replace("/n","/")

Profundizando más: se pueden observar comportamientos aún más extraños cuando probamos otras entradas.

Permite asignar text="Hello/nWorld/n"

Ahora, text.replaceAll("/n","/") , text.replaceAll("//n","/") , text.replaceAll("///n","/") todos estos tres dan el mismo resultado Hello/World/

¡Java realmente se había equivocado con el reg-ex de la mejor manera posible que siento! Ningún otro idioma parece tener estos comportamientos lúdicos en reg-ex. Cualquier razón específica, ¿por qué Java se equivocó así?


Necesitas tener esacpe dos veces, una vez para Java, una vez para la expresión regular.

El código de Java es

"////"

hace una cadena de expresiones regulares de

"//" - two chars

pero la expresión regular también necesita un escape por lo que se convierte en

/ - one symbol


Una forma de evitar este problema es reemplazar la barra invertida con otro carácter, usar ese carácter de sustituto para reemplazos intermedios, y luego convertirlo de nuevo en barra invertida al final. Por ejemplo, para convertir "/ r / n" en "/ n":

String out = in.replace(''//',''@'').replaceAll("@r@n","@n").replace(''@'',''//');

Por supuesto, eso no funcionará muy bien si elige un personaje de reemplazo que pueda aparecer en la cadena de entrada.


Creo que Java realmente se metió con la expresión regular en String.replaceAll ();

Además de java, nunca he visto un lenguaje analizar la expresión regular de esta manera. Se confundirá si ha utilizado expresiones regulares en algunos otros idiomas.

En caso de utilizar la "//" en la cadena de reemplazo, puede usar java.util.regex.Matcher.quoteReplacement(String)

String.replaceAll("/", Matcher.quoteReplacement("//"));

Al usar esta clase de Matcher puede obtener el resultado esperado.


Simplemente otra forma de explicar estas 4 barras diagonales inversas.

1) Supongamos que quiere reemplazar un único / utilizando el método replaceAll de Java:

/ ˪--- 1) the final backslash

2) El método replaceAll de Java toma una expresión regular como primer argumento. En un literal de expresión regular , / tiene un significado especial, por ejemplo, en /d que es un atajo para [0-9] (cualquier dígito). La forma de escapar de un metachar en un literal de expresión regular es precederlo con un / , lo que conduce a:

// |˪--- 1) the final backslash ˪---- 2) the backslash needed to escape 1) in a regex literal

3) En Java, no hay literal regex : usted escribe una expresión regular en un literal de cadena (a diferencia de JavaScript, por ejemplo, donde puede escribir //d+/ ). Pero en un literal de cadena , / también tiene un significado especial, por ejemplo, en /n (una nueva línea) o /t (una pestaña). La forma de escapar de un metachar en un literal de cadena es precederlo con un / , lo que conduce a:

//// |||˪--- 1) the final backslash ||˪---- 3) the backslash needed to escape 1) in a string literal |˪----- 2) the backslash needed to escape 1) in a regex literal ˪------ 3) the backslash needed to escape 2) in a string literal


La respuesta de Peter Lawrey describe la mecánica. El "problema" es que la barra diagonal inversa es un carácter de escape en ambos literales de cadena de Java, y en el mini-lenguaje de expresiones regulares. Entonces, cuando usa un literal de cadena para representar una expresión regular, hay que considerar dos conjuntos de escapes ... dependiendo de lo que quiera que signifique la expresión regular.

Pero, ¿por qué es así?

Es algo histórico. Java originalmente no tenía expresiones regulares en absoluto. Las reglas de sintaxis para los literales de Java String fueron tomadas de C / C ++, que tampoco tenía soporte de expresiones regulares incorporado. La torpeza del doble escape no se hizo evidente en Java hasta que agregaron soporte de expresiones regulares en la forma de la clase de Pattern ... en Java 1.4.

Entonces, ¿cómo otros idiomas logran evitar esto?

Lo hacen al proporcionar soporte sintáctico directo o indirecto para las expresiones regulares en el lenguaje de programación en sí . Por ejemplo, en Perl, Ruby, Javascript y muchos otros lenguajes, hay una sintaxis para patrones / expresiones regulares (por ejemplo, ''/ patrón /'') donde no se aplican las reglas de escape de cadenas literales. En C # y Python, proporcionan una sintaxis literal de cadena "en bruto" alternativa en la que las barras diagonales inversas no son escapes. (Pero tenga en cuenta que si usa la sintaxis de cadena C # / Python normal, tiene el problema de Java de doble escape).

¿Por qué text.replaceAll("/n","/") , text.replaceAll("//n","/") y text.replaceAll("///n","/") dan todos los misma salida?

El primer caso es un carácter de nueva línea en el nivel de Cadena. El lenguaje de expresiones regulares de Java trata todos los caracteres no especiales para que coincidan.

El segundo caso es una barra invertida seguida de una "n" en el nivel de cadena. El lenguaje regex de Java interpreta una barra invertida seguida de una "n" como una nueva línea.

El último caso es una barra invertida seguida de un carácter de línea nueva en el nivel de cadena. El lenguaje regex de Java no reconoce esto como una secuencia de escape específica (regex). Sin embargo, una barra invertida seguida de cualquier carácter no alfabético significa el último carácter. Entonces, una barra invertida seguida de un carácter de nueva línea ... significa lo mismo que una nueva línea.