Lista de todos los caracteres especiales que deben escaparse en una expresión regular

108

Estoy intentando crear una aplicación que coincida con una plantilla de mensaje con un mensaje que un usuario está intentando enviar. Estoy usando Java regex para hacer coincidir el mensaje. La plantilla / mensaje puede contener caracteres especiales.

¿Cómo obtendría la lista completa de caracteres especiales que deben escaparse para que mi expresión regular funcione y coincida en el máximo de casos posibles?

¿Existe una solución universal para escapar de todos los caracteres especiales en Java regex?

Avinash Nair
fuente

Respuestas:

94

Puede ver el javadoc de la clase Pattern: http://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html

Debe escapar de cualquier carácter enumerado allí si desea el carácter regular y no el significado especial.

Como una solución tal vez más simple, puede colocar la plantilla entre \ Q y \ E; todo lo que hay entre ellos se considera escapado.

Sorin
fuente
43
Si encuentra que \ Q y \ E son difíciles de recordar, puede usar Pattern.quote ("...")
mkdev
19
Ojalá las hubieras dicho
Aleksandr Dubinsky
¿Por qué, @AleksandrDubinsky?
Sorin
55
@Sorin Porque el espíritu (¿no, la política?) De Stack Exchange es indicar la respuesta en su respuesta en lugar de simplemente vincularla a un recurso externo. Además, esa página tampoco tiene una lista clara. Puede encontrar una lista aquí: docs.oracle.com/javase/tutorial/essential/regex/literals.html , sin embargo, dice "En ciertas situaciones, los caracteres especiales enumerados anteriormente no se tratarán como metacaracteres", sin explicar lo que sucederá. si uno intenta escapar de ellos. En resumen, esta pregunta merece una buena respuesta.
Aleksandr Dubinsky
8
"todo entre ellos [ \Qy \E] se considera escapado" , excepto los de otros \Qy \E(que potencialmente pueden ocurrir dentro de la expresión regular original). Por lo tanto, es mejor usarlo Pattern.quotecomo se sugiere aquí y no reinventar la rueda.
Sasha
92
  • Los caracteres de Java que deben escaparse en expresiones regulares son:
    \.[]{}()<>*+-=!?^$|
  • Solo es necesario escapar dos de los soportes de cierre ( ]y }) después de abrir el mismo tipo de soporte.
  • Entre []paréntesis, algunos caracteres (como +y -) a veces funcionan sin escape.
Demasiado grande.
fuente
¿Hay alguna forma de no escapar pero permitir a esos personajes?
Dominika
1
Escapar de un carácter significa permitir el carácter en lugar de interpretarlo como un operador.
Tobi G.
4
Es posible que el -interior sin escape []no siempre funcione, ya que se utiliza para definir rangos. Es más seguro escapar de él. Por ejemplo, los patrones [-]y [-)]coinciden con la cadena -pero no con [(-)].
Kenston Choi
1
Aunque la respuesta aceptada responde a la pregunta, esta respuesta me resultó más útil cuando solo buscaba una lista rápida.
Old Nick
-=!no necesariamente es necesario escapar, depende del contexto. Por ejemplo, como una sola letra, funcionan como una expresión regular constante.
Hawk
29

Para escapar, puede usar esto de Java 1.5 :

Pattern.quote("$test");

Coincidirás exactamente con la palabra $test

madx
fuente
¿Por qué esta no es la respuesta mejor valorada? Resuelve el problema sin entrar en los complejos detalles de enumerar todos los caracteres que necesitan escapar y es parte del JDK, ¡no es necesario escribir ningún código adicional! ¡Sencillo!
Volksman
17

De acuerdo con la página de documentación de String Literals / Metacharacters , son:

<([{\^-=$!|]})?*+.>

También sería genial tener esa lista referenciada en algún lugar del código, pero no sé dónde podría estar ...

Bohdan
fuente
11
String escaped = tnk.replaceAll("[\\<\\(\\[\\{\\\\\\^\\-\\=\\$\\!\\|\\]\\}\\)\\?\\*\\+\\.\\>]", "\\\\$0");
marbel82
1
El javadoc Pattern dice que es un error usar una barra invertida antes de cualquier carácter alfabético que no denota una construcción de escape, pero se puede usar una barra invertida antes de un carácter no alfabético independientemente de si ese carácter es parte de una construcción sin escape. Por lo tanto, una expresión regular mucho más simple será suficiente: s.replaceAll("[\\W]", "\\\\$0")donde \Wdesigna caracteres que no son palabras.
Joe Bowbeer
6

Combinando lo que todos dijeron, propongo lo siguiente, para mantener la lista de caracteres especiales para RegExp claramente enumerados en su propia Cadena, y para evitar tener que intentar analizar visualmente miles de "\\". Esto parece funcionar bastante bien para mí:

final String regExSpecialChars = "<([{\\^-=$!|]})?*+.>";
final String regExSpecialCharsRE = regExSpecialChars.replaceAll( ".", "\\\\$0");
final Pattern reCharsREP = Pattern.compile( "[" + regExSpecialCharsRE + "]");

String quoteRegExSpecialChars( String s)
{
    Matcher m = reCharsREP.matcher( s);
    return m.replaceAll( "\\\\$0");
}
NeuroDuck
fuente
5

En la sugerencia de @ Sorin de los documentos de Java Pattern, parece que los caracteres para escapar son al menos:

\.[{(*+?^$|
pete
fuente
4
String escaped = regexString.replaceAll("([\\\\\\.\\[\\{\\(\\*\\+\\?\\^\\$\\|])", "\\\\$1");
fracz
2
)también tiene que ser escapado, y dependiendo de si estás dentro o fuera de una clase de personaje, puede haber más personajes para escapar, en cuyo caso Pattern.quotehace un buen trabajo al escapar de una cadena para usar tanto dentro como fuera de la clase de personaje.
nhahtdh
3

El Pattern.quote(String s)tipo de hace lo que quieres. Sin embargo, deja un poco que desear; en realidad no se escapa de los caracteres individuales, solo envuelve la cadena con \Q...\E.

No existe un método que haga exactamente lo que está buscando, pero la buena noticia es que en realidad es bastante simple escapar de todos los caracteres especiales en una expresión regular de Java:

regex.replaceAll("[\\W]", "\\\\$0")

¿Por qué funciona esto? Bueno, la documentación para Patternespecíficamente dice que está permitido escapar de los caracteres no alfabéticos que no necesariamente tienen que escaparse:

Es un error usar una barra invertida antes de cualquier carácter alfabético que no denote una construcción de escape; estos están reservados para futuras extensiones del lenguaje de expresiones regulares. Se puede usar una barra invertida antes de un carácter no alfabético independientemente de si ese carácter es parte de una construcción sin escape.

Por ejemplo, ;no es un carácter especial en una expresión regular. Sin embargo, si lo escapas, Patternaún se interpretará \;como ;. Aqui hay algunos ejemplos mas:

  • >se convierte en lo \>que es equivalente a>
  • [se convierte en \[cuál es la forma escapada de[
  • 8está quieto 8.
  • \)se convierte en lo \\\)que son las formas escapadas \y (concatenadas.

Nota: La clave es la definición de "no alfabético", que en la documentación realmente significa caracteres "que no son palabras " o caracteres fuera del conjunto de caracteres [a-zA-Z_0-9].

rodador
fuente
2

En el otro lado de la moneda, debe usar expresiones regulares "sin caracteres" que se vean así si los caracteres especiales = allChars - número - ABC - espacio en el contexto de su aplicación.

String regepx = "[^\\s\\w]*";
Bo6Bear
fuente
2

aunque la respuesta es para Java, pero el código se puede adaptar fácilmente de esta extensión de Kotlin String que se me ocurrió (adaptado de la que @brcolow proporcionó):

private val escapeChars = charArrayOf(
    '<',
    '(',
    '[',
    '{',
    '\\',
    '^',
    '-',
    '=',
    '$',
    '!',
    '|',
    ']',
    '}',
    ')',
    '?',
    '*',
    '+',
    '.',
    '>'
)

fun String.escapePattern(): String {
    return this.fold("") {
      acc, chr ->
        acc + if (escapeChars.contains(chr)) "\\$chr" else "$chr"
    }
}

fun main() {
    println("(.*)".escapePattern())
}

huellas dactilares \(\.\*\)

compruébalo en acción aquí https://pl.kotl.in/h-3mXZkNE

pocesar
fuente
1

Suponiendo que tiene y confía (para ser autorizado) la lista de caracteres de escape que usa Java regex (sería bueno si estos caracteres estuvieran expuestos en algún miembro de la clase Pattern), puede usar el siguiente método para escapar del carácter si es realmente necesario:

private static final char[] escapeChars = { '<', '(', '[', '{', '\\', '^', '-', '=', '$', '!', '|', ']', '}', ')', '?', '*', '+', '.', '>' };

private static String regexEscape(char character) {
    for (char escapeChar : escapeChars) {
        if (character == escapeChar) {
            return "\\" + character;
        }
    }
    return String.valueOf(character);
}
brcolow
fuente