¿Qué caracteres especiales se deben escapar en expresiones regulares?

389

Estoy cansado de siempre tratar de adivinar si debo escapar de caracteres especiales como ' ()[]{}|' etc., cuando uso muchas implementaciones de expresiones regulares.

Es diferente con, por ejemplo, Python, sed, grep, awk, Perl, renombrar, Apache, find, etc. ¿Existe algún conjunto de reglas que indique cuándo debería y cuándo no debería escapar de caracteres especiales? ¿Depende del tipo de expresiones regulares, como PCRE, POSIX o expresiones regulares extendidas?

Igor Katson
fuente
44
Las buenas bibliotecas de expresiones regulares tienen funciones como " escape()" para permitir el uso de cadenas arbitrarias como partes de expresiones regulares.
ivan_pozdeev
2
Puede usar los verificadores de expresiones de Regex en línea como gskinner.com/RegExr (es gratis). (Escribe, luego pasa el mouse sobre la expresión regular que
escribiste
2
Escapar de todos los caracteres no alfanuméricos. período.
Salman von Abbas
2
Esta pregunta se ha agregado a las Preguntas frecuentes sobre Expresión regular de desbordamiento de pila , en "Otro".
aliteralmind
1
Esta pregunta se ha agregado a las Preguntas frecuentes sobre Expresión regular de desbordamiento de pila , en "Secuencias de escape".
aliteralmind

Respuestas:

365

Los personajes que debes y de los que no debes escapar dependen del sabor de expresiones regulares con el que estés trabajando.

Para PCRE, y la mayoría de los otros sabores llamados compatibles con Perl, escapa de estas clases de caracteres externos:

.^$*+?()[{\|

y estas clases de personajes internos:

^-]\

Para las expresiones regulares extendidas POSIX (ERE), escape de estas clases de caracteres externas (igual que PCRE):

.^$*+?()[{\|

Escapar de cualquier otro personaje es un error con POSIX ERE.

Dentro de las clases de caracteres, la barra diagonal inversa es un carácter literal en las expresiones regulares POSIX. No puedes usarlo para escapar de nada. Debe usar "colocación inteligente" si desea incluir metacaracteres de clase de caracteres como literales. Coloque ^ en cualquier lugar excepto al principio, el] al comienzo y el - al comienzo o al final de la clase de caracteres para que coincidan literalmente, por ejemplo:

[]^-]

En las expresiones regulares básicas POSIX (BRE), estos son metacaracteres de los que debe escapar para suprimir su significado:

.^$*[\

Escapar de paréntesis y llaves en BRE les da el significado especial que tienen sus versiones sin escape en ERE. Algunas implementaciones (por ejemplo, GNU) también dan un significado especial a otros caracteres cuando se escapan, como \? y +. Escapar de un carácter que no sea. ^ $ * () {} Es normalmente un error con BRE.

Dentro de las clases de personajes, los BRE siguen la misma regla que los ERE.

Si todo esto te hace girar la cabeza, toma una copia de RegexBuddy . En la pestaña Crear, haga clic en Insertar token y luego en Literal. RegexBuddy agregará escapes según sea necesario.

Jan Goyvaerts
fuente
1
Me parece que olvidó el "/", que también debe escaparse fuera de una clase.
jackthehipster
11
/no es un metacarácter en ninguno de los sabores de expresión regular que mencioné, por lo que la sintaxis de expresión regular no requiere escapar. Cuando una expresión regular es citado como un literal en un lenguaje de programación, a continuación, las reglas de cadenas o expresiones regulares formateo de que el lenguaje pueden requerir /o "o 'ser escapado, e incluso pueden requerir `\` para ser doblemente escapado.
Jan Goyvaerts
2
¿Qué pasa con el colon, ":"? ¿Se escapará dentro de las clases de personajes y afuera? en.wikipedia.org/wiki/Perl_Compatible_Regular_Expressions dice "PCRE tiene reglas de escape consistentes: cualquier carácter no alfanumérico puede escapar a su valor literal [...]"
nicolallias
44
PUEDE escapar no es lo mismo que DEBE escapar. La sintaxis PCRE nunca requiere que se escapen dos puntos literales, por lo que escapar de dos puntos literales solo hace que su expresión regular sea más difícil de leer.
Jan Goyvaerts
1
Para ERE no POSIX (el que uso con más frecuencia porque es lo que implementa Tcl) escapar de otras cosas no genera errores.
slebetman
61

Sabores RegEx modernos (PCRE)

Incluye C, C ++, Delphi, EditPad, Java, JavaScript, Perl, PHP (preg), PostgreSQL, PowerGREP, PowerShell, Python, REALbasic, Real Studio, Ruby, TCL, VB.Net, VBScript, wxWidgets, XML Schema, Xojo, XRegExp.
La compatibilidad con PCRE puede variar

    En cualquier sitio: . ^ $ * + - ? ( ) [ ] { } \ |


Sabores Legacy RegEx (BRE / ERE)

Incluye awk, ed, egrep, emacs, GNUlib, grep, PHP (ereg), MySQL, Oracle, R, sed.
El soporte PCRE puede habilitarse en versiones posteriores o mediante el uso de extensiones

ERE / awk / egrep / emacs

    Fuera de una clase de personaje: . ^ $ * + ? ( ) [ { } \ |
    Dentro de una clase de personaje:^ - [ ]

BRE / ed / grep / sed

    Fuera de una clase de caracteres: . ^ $ * [ \
    Dentro de una clase de caracteres: ^ - [ ]
    Para literales, no escape: + ? ( ) { } |
    Para el comportamiento estándar de expresiones regulares, escape:\+ \? \( \) \{ \} \|


Notas

  • Si no está seguro acerca de un personaje específico, se puede escapar como \xFF
  • Los caracteres alfanuméricos no se pueden escapar con una barra invertida
  • Los símbolos arbitrarios se pueden escapar con una barra diagonal inversa en PCRE, pero no BRE / ERE (solo se deben escapar cuando sea necesario). Para PCRE ] -solo necesito escapar dentro de una clase de caracteres, pero los mantuve en una sola lista por simplicidad
  • Las cadenas de expresión entre comillas también deben tener los caracteres de comillas circundantes escapados, y a menudo con barras invertidas duplicadas (como "(\")(/)(\\.)"versus /(")(\/)(\.)/en JavaScript)
  • Además de los escapes, las diferentes implementaciones de expresiones regulares pueden admitir diferentes modificadores, clases de caracteres, anclajes, cuantificadores y otras características. Para más detalles, visite regular-expressions.info , o use regex101.com para probar sus expresiones en vivo
Beejor
fuente
1
Hay muchos errores en su respuesta, incluidos, entre otros: Ninguno de sus sabores "modernos" requiere -o ]debe escaparse fuera de las clases de caracteres. POSIX (BRE / ERE) no tiene un carácter de escape dentro de las clases de caracteres. El sabor regex en RTL de Delphi se basa realmente en PCRE. Python, Ruby y XML tienen sus propios sabores que están más cerca de PCRE que de los sabores POSIX.
Jan Goyvaerts
1
@ JanGoyvaerts Gracias por la corrección. Los sabores que mencionó están realmente más cerca de PCRE. En cuanto a los escapes, los mantuve así por simplicidad; Es más fácil recordar escapar por todas partes que algunas excepciones. Los usuarios avanzados sabrán lo que pasa, si quieren evitar algunas barras invertidas. De todos modos, actualicé mi respuesta con algunas aclaraciones que espero aborden algunas de estas cosas.
Beejor
22

Desafortunadamente, realmente no hay un conjunto de códigos de escape ya que varía según el idioma que esté utilizando.

Sin embargo, mantener una página como la Página de herramientas de expresión regular o esta Cheatsheet de expresión regular puede ser de gran ayuda para ayudarlo a filtrar rápidamente las cosas.

Dillie-O
fuente
1
La hoja de trucos de Addedbytes está excesivamente simplificada y tiene algunos errores evidentes. Por ejemplo, dice \<y \>son límites de palabras, lo cual es cierto solo (AFAIK) en la biblioteca Boge regex. Pero en otra parte dice <y >son metacaracteres y deben escaparse (hacia \<y \>) para que coincidan literalmente, lo cual no es cierto en ningún sentido
Alan Moore
5

Desafortunadamente, el significado de cosas como (y \ (se intercambian entre las expresiones regulares de estilo de Emacs y la mayoría de los otros estilos. Por lo tanto, si intenta escapar de estas, puede estar haciendo lo contrario de lo que desea).

Entonces realmente tienes que saber qué estilo estás tratando de citar.

Darron
fuente
5

POSIX reconoce múltiples variaciones en expresiones regulares: expresiones regulares básicas (BRE) y expresiones regulares extendidas (ERE). E incluso entonces, hay peculiaridades debido a las implementaciones históricas de las utilidades estandarizadas por POSIX.

No hay una regla simple sobre cuándo usar qué notación, o incluso qué notación usa un comando dado.

Echa un vistazo al libro Mastering Regular Expressions de Jeff Friedl .

Jonathan Leffler
fuente
4

Realmente no lo hay. hay aproximadamente medio millón de sintaxis de expresiones regulares diferentes; Parece que se reducen a Perl, EMACS / GNU y AT&T en general, pero también siempre me sorprende.

Charlie Martin
fuente
4

A veces, el escape simple no es posible con los personajes que has enumerado. Por ejemplo, usar una barra invertida para escapar de un soporte no va a funcionar en el lado izquierdo de una cadena de sustitución en sed, es decir

sed -e 's/foo\(bar/something_else/'

Tiendo a usar una simple definición de clase de caracteres en su lugar, por lo que la expresión anterior se convierte en

sed -e 's/foo[(]bar/something_else/'

que encuentro funciona para la mayoría de las implementaciones de expresiones regulares.

Por cierto, las clases de caracteres son componentes de expresión regular bastante vainilla, por lo que tienden a funcionar en la mayoría de las situaciones en las que se necesitan caracteres escapados en expresiones regulares.

Editar: después del comentario a continuación, solo pensé en mencionar el hecho de que también debe considerar la diferencia entre autómatas de estado finito y autómatas de estado no finito al observar el comportamiento de la evaluación de expresiones regulares.

Es posible que desee ver "el libro de la bola brillante", también conocido como Effective Perl ( enlace Amazon desinfectado ), específicamente el capítulo sobre expresiones regulares, para tener una idea de la diferencia en los tipos de evaluación del motor regexp.

¡No todo el mundo es un PCRE!

De todos modos, ¡las expresiones regulares son tan torpes en comparación con SNOBOL ! ¡Ese sí que fue un curso de programación interesante! Junto con el de Simula .

¡Ah, la alegría de estudiar en UNSW a finales de los 70! (-:

Rob Wells
fuente
'sed' es un comando para el que plain '(' no es especial pero '\ (' es especial; en contraste, PCRE invierte el sentido, entonces '(' es especial, pero '\ (' no lo es. Esto es exactamente lo que el OP pregunta por.
Jonathan Leffler
sed es una utilidad * nix que utiliza uno de los conjuntos más primitivos de evaluación regexp. PCRE no entra en la situación que describo, ya que involucra una clase diferente de autómatas (in) finitos con la forma en que evalúa las expresiones regulares. Creo que mi sugerencia para el conjunto mínimo de sintaxis regexp aún se mantiene.
Rob Wells
1
En un sistema compatible con POSIX, sed usa POSIX BRE, que cubro en mi respuesta. La versión GNU en el sistema Linux moderno usa POSIX BRE con algunas extensiones.
Jan Goyvaerts
2

Para PHP, "siempre es seguro preceder un no alfanumérico con" \ "para especificar que se defiende a sí mismo". - http://php.net/manual/en/regexp.reference.escape.php .

Excepto si es un "o".: /

Para escapar de las variables de patrón regex (o variables parciales) en PHP, use preg_quote ()

zylstra
fuente
2

Para saber cuándo y qué escapar sin intentos es necesario comprender con precisión la cadena de contextos por los que pasa la cadena. Especificará la cadena desde el lado más alejado hasta su destino final, que es la memoria manejada por el código de análisis regexp.

Tenga en cuenta cómo se procesa la cadena en la memoria: si puede ser una cadena simple dentro del código, o una cadena ingresada en la línea de comando, pero podría ser una línea de comando interactiva o una línea de comando dentro de un archivo de script de shell, o dentro de una variable en la memoria mencionada por el código, o un argumento (cadena) a través de una evaluación adicional, o una cadena que contiene código generado dinámicamente con cualquier tipo de encapsulación ...

Cada uno de este contexto asignó algunos caracteres con una funcionalidad especial.

Cuando desee pasar el carácter literalmente sin usar su función especial (local al contexto), entonces ese es el caso que tiene que escapar, para el siguiente contexto ... que podría necesitar algunos otros caracteres de escape que también podrían ser necesarios. escapado en los contextos anteriores. Además, puede haber cosas como la codificación de caracteres (el más insidioso es utf-8 porque parece ASCII para caracteres comunes, pero puede ser interpretado opcionalmente incluso por el terminal dependiendo de su configuración para que pueda comportarse de manera diferente, entonces el atributo de codificación de HTML / XML, es necesario comprender el proceso con precisión.

Por ejemplo, una expresión regular en la línea de comando que comienza con perl -npe, debe transferirse a un conjunto de llamadas al sistema exec que se conectan como canalizaciones que maneja el archivo, cada una de estas llamadas al sistema exec solo tiene una lista de argumentos separados por espacios (no escapados), y posiblemente tuberías (|) y redirección (> N> N> & M), paréntesis, expansión interactiva de *y ?,$(())... (todo esto son caracteres especiales usados ​​por * sh que pueden parecer que interfieren con el carácter de la expresión regular en el siguiente contexto, pero se evalúan en orden: antes de la línea de comando. La línea de comando es leída por un programa como bash / sh / csh / tcsh / zsh, esencialmente dentro de comillas dobles o comillas simples, el escape es más simple, pero no es necesario citar una cadena en la línea de comando porque la mayoría del espacio tiene que estar prefijado con una barra diagonal inversa y la cita es no es necesario dejar disponible la funcionalidad de expansión para los caracteres * y?, pero esto se analiza en un contexto diferente al de la comilla. Luego, cuando se evalúa la línea de comando, la expresión regular obtenida en la memoria (no como está escrita en la línea de comando) recibe el mismo tratamiento que estaría en un archivo fuente. Para regexp hay un contexto de juego de caracteres entre corchetes [],La expresión regular perl se puede citar mediante un gran conjunto de caracteres no alfa-numéricos (por ejemplo, m // or m: / better / for / path: ...).

Tiene más detalles sobre los caracteres en otra respuesta, que son muy específicos para el contexto final de expresiones regulares. Como mencioné, mencionas que encuentras el escape regexp con intentos, probablemente porque un contexto diferente tiene un conjunto diferente de caracteres que confunde tu memoria de intentos (a menudo la barra diagonal inversa es el carácter utilizado en esos contextos diferentes para escapar de un carácter literal en lugar de su función )

Marco Munari
fuente
0

Para Ionic (mecanografiado), debe hacer una doble barra para escapar de los caracteres. Por ejemplo (esto es para que coincida con algunos caracteres especiales):

"^(?=.*[\\]\\[!¡\'=ªº\\-\\_ç@#$%^&*(),;\\.?\":{}|<>\+\\/])"

Presta atención a estos ] [ - _ . /personajes. Tienen que ser doblemente cortadas. Si no hace eso, tendrá un error de tipo en su código.

Alejandro del Río
fuente