GNU/Linux >> Tutoriales Linux >  >> Linux

¿Por qué la expresión regular funciona en X pero no en Y?

Escribí una expresión regular que funciona bien en cierto programa (grep, sed, awk, perl, python, ruby, ksh, bash, zsh, find, emacs, vi, vim, gedit, …). Pero cuando lo uso en un programa diferente (o en una variante diferente de Unix), deja de coincidir. ¿Por qué?

Respuesta aceptada:

Desafortunadamente, por razones históricas, diferentes herramientas tienen una sintaxis de expresión regular ligeramente diferente y, a veces, algunas implementaciones tienen extensiones que no son compatibles con otras herramientas. Si bien hay un terreno común, parece que cada diseñador de herramientas tomó algunas decisiones diferentes.

La consecuencia es que si tiene una expresión regular que funciona en una herramienta, es posible que deba modificarla para que funcione en otra herramienta. Las principales diferencias entre las herramientas comunes son:

  • si los operadores +?|(){} requieren una barra invertida;
  • qué extensiones son compatibles además de las básicas .[]*^$ y normalmente +?|()

En esta respuesta, enumero los principales estándares. Consulte la documentación de las herramientas que está utilizando para conocer los detalles.

La comparación de motores de expresiones regulares de Wikipedia tiene una tabla que enumera las funciones compatibles con las implementaciones comunes.

Expresiones regulares básicas (BRE)

Las expresiones regulares básicas están codificadas por el estándar POSIX. Es la sintaxis usada por grep , sed y vi . Esta sintaxis proporciona las siguientes funciones:

  • ^ y $ coincide solo al principio y al final de una línea.
  • . coincide con cualquier carácter (o cualquier carácter excepto una nueva línea).
  • […] coincide con cualquier carácter enumerado dentro de los corchetes (conjunto de caracteres). Si el primer carácter después del paréntesis de apertura es un ^ , los caracteres que no aparecen en la lista se comparan en su lugar. Para incluir un ] , póngalo inmediatamente después de la apertura [ (o después de [^ si es un conjunto negativo). Si - está entre dos caracteres, denota un rango; para incluir un literal - , colóquelo donde no se pueda analizar como un rango.
  • barra invertida antes de cualquiera de ^$.*[ cita el siguiente carácter.
  • * coincide con el carácter anterior o la subexpresión 0, 1 o más veces.
  • (…) es un grupo sintáctico, para usar con * operador o referencias inversas y DIGIT reemplazos.
  • Referencias 1 , 2 , … coincide con el texto exacto que coincide con el grupo correspondiente, p. (fo*)(ba*)1 coincide con foobaafoo pero no foobaafo . No existe una forma estándar de referirse al décimo grupo y más allá (el significado estándar de 10 es el primer grupo seguido de un ).

Las siguientes características también son estándar, pero faltan en algunas implementaciones restringidas:

  • {m,n} coincide con el carácter anterior o la subexpresión entre m a n veces; n o m se puede omitir, y {m} significa exactamente m .
  • Dentro de corchetes, se pueden usar clases de caracteres, por ejemplo [[:alpha:]] coincide con cualquier letra. Las implementaciones modernas de expresiones entre paréntesis) también incluyen elementos de clasificación como [.ll.] y clases de equivalencia como [=a=] .

Las siguientes son extensiones comunes (especialmente en herramientas GNU), pero no se encuentran en todas las implementaciones. Consulte el manual de la herramienta que está utilizando.

  • | para alternancia:foo|bar coincide con foo o bar .
  • ? (abreviatura de {0,1} ) y + (abreviatura de {1,} ) coincide con el carácter anterior o la subexpresión como máximo 1 vez, o al menos 1 vez respectivamente.
  • n coincide con una nueva línea, t coincide con una pestaña, etc.
  • w coincide con cualquier componente de la palabra (abreviatura de [_[:alnum:]] pero con variaciones cuando se trata de localización) y W coincide con cualquier carácter que no sea un componente de la palabra.
  • < y > hacer coincidir la cadena vacía solo al principio o al final de una palabra, respectivamente; b coincide con cualquiera, y B coincide donde b no.

Tenga en cuenta que las herramientas sin | El operador no tiene todo el poder de las expresiones regulares. Las referencias inversas permiten algunas cosas adicionales que no se pueden hacer con expresiones regulares en el sentido matemático.

Expresiones regulares extendidas (ERE)

Las expresiones regulares extendidas están codificadas por el estándar POSIX. Su principal ventaja sobre BRE es la regularidad:todos los operadores estándar son caracteres de puntuación simples, una barra invertida antes de un carácter de puntuación siempre lo cita. Es la sintaxis usada por awk , grep -E o egrep , GNU sed -r y bash =~ operador. Esta sintaxis proporciona las siguientes funciones:

  • ^ y $ coincide solo al principio y al final de una línea.
  • . coincide con cualquier carácter (o cualquier carácter excepto una nueva línea).
  • […] coincide con cualquier carácter enumerado dentro de los corchetes (conjunto de caracteres). Complementación con un ^ inicial y los rangos funcionan como en BRE (ver arriba). Las clases de caracteres se pueden usar, pero faltan en algunas implementaciones. Las implementaciones modernas también admiten clases de equivalencia y elementos de clasificación. Una barra invertida entre corchetes cita el siguiente carácter en algunas pero no en todas las implementaciones; usar \ significa una barra invertida para la portabilidad.
  • (…) es un grupo sintáctico, para usar con * o DIGIT reemplazos.
  • | para alternancia:foo|bar coincide con foo o bar .
  • * , + y ? coincide con el carácter anterior o la subexpresión varias veces:0 o más para * , 1 o más para + , 0 o 1 para ? .
  • La barra invertida cita el siguiente carácter si no es alfanumérico.
  • {m,n} coincide con el carácter anterior o la subexpresión entre m y n veces (falta en algunas implementaciones); n o m se puede omitir, y {m} significa exactamente m .
  • Algunas extensiones comunes como en BRE:DIGIT referencias inversas (notablemente ausentes en awk excepto en la implementación de busybox donde puede usar $0 ~ "(...)\1" ); caracteres especiales n , t , etc.; límites de palabras b y B , componentes de la palabra b y B , …
Relacionado:mi teoría anterior estaba equivocada, entonces, ¿por qué funciona esto?

PCRE (expresiones regulares compatibles con Perl)

PCRE son extensiones de ERE, introducidas originalmente por Perl y adoptadas por GNU grep -P y muchas herramientas modernas y lenguajes de programación , generalmente a través de la biblioteca PCRE. Consulte la documentación de Perl para obtener un buen formato con ejemplos. No todas las características de la última versión de Perl son compatibles con PCRE (por ejemplo, la ejecución de código Perl solo es compatible con Perl). Consulte el manual de PCRE para obtener un resumen de las funciones admitidas. Las principales incorporaciones al ERE son:

  • (?:…) es un grupo que no captura:como (…) , pero no cuenta para las referencias anteriores.
  • (?=FOO)BAR (previsión) coincide con BAR , pero solo si también hay una coincidencia para FOO comenzando en la misma posición. Esto es más útil para anclar una coincidencia sin incluir el siguiente texto en la coincidencia:foo(?=bar) coincide con foo pero solo si va seguido de bar .
  • (?!FOO)BAR (anticipación negativa) coincide con BAR , pero tampoco hay una coincidencia para FOO en la misma posición. Por ejemplo (?!foo)[a-z]+ coincide con cualquier palabra en minúscula que no comience con foo; [a-z]+(?![0-9) coincide con cualquier palabra en minúscula que no vaya seguida de un dígito (por lo tanto, en foo123 , coincide con fo pero no foo ).
  • (?<=FOO)BAR (mirar atrás) coincide con BAR , pero solo si está inmediatamente precedido por una coincidencia para FOO . FOO debe tener una longitud conocida (no puede usar operadores de repetición como * ). Esto es más útil para anclar una coincidencia sin incluir el texto anterior en la coincidencia:(?<=^| )foo coincide con foo pero solo si está precedido por un espacio o por el comienzo de la cadena.
  • (?<!FOO)BAR (mirada atrás negativa) coincide con BAR , pero solo si no está inmediatamente precedido por una coincidencia para FOO . FOO debe tener una longitud conocida (no puede usar operadores de repetición como * ). Esto es más útil para anclar una coincidencia sin incluir el texto anterior en la coincidencia:(?<![a-z])foo coincide con foo pero solo si no va precedida de una letra minúscula.

Emac

La sintaxis de Emacs es intermedia entre BRE y ERE. Además de Emacs, es la sintaxis predeterminada para -regex en GNU encontrar. Emacs ofrece los siguientes operadores:

  • ^ , $ , . , […] , * , + , ? como en ERE
  • (…) , | , {…} , DIGIT como en BRE
  • más secuencias de letras con barra invertida; < y > para límites de palabras; y más en versiones recientes de Emacs, que a menudo no son compatibles con otros motores con una sintaxis similar a Emacs.
Relacionado:¿Usar buscar para encontrar cierto directorio y eliminar todos los archivos excepto un directorio?

Globos de concha

Shell globs (comodines) realizan coincidencias de patrones con una sintaxis que es completamente diferente de las expresiones regulares y menos potente. Además de shells, estos comodines están disponibles con otras herramientas como find -name y filtros rsync. Los patrones POSIX incluyen las siguientes características:

  • ? coincide con cualquier carácter individual.
  • […] es un conjunto de caracteres como en las sintaxis de expresiones regulares comunes. Algunos shells no admiten clases de caracteres. Algunos shells requieren ! en lugar de ^ para negar el conjunto.
  • * coincide con cualquier secuencia de caracteres (a menudo excepto / al hacer coincidir rutas de archivos; si / está excluido de * , luego ** a veces incluye / , pero consulte la documentación de la herramienta).
  • La barra invertida cita el siguiente carácter.

Ksh ofrece funciones adicionales que hacen que su patrón coincida con todo el poder de las expresiones regulares. Estas funciones también están disponibles en bash después de ejecutar shopt -s extglob . Zsh tiene una sintaxis diferente pero también puede admitir la sintaxis de ksh después de setopt ksh_glob .


Linux
  1. ¿Por qué `md5sum` no da el mismo hash que Internet?

  2. ¿Por qué el archivo de traducción de Bash no contiene todos los textos de error?

  3. Linux:¿por qué no funciona Setuid?

  4. ¿Por qué `zip` en un bucle For funciona cuando el archivo existe, pero no cuando no existe?

  5. ¿Por qué este "mientras se lee" funciona en una terminal, pero no en un script de Shell?

Linux – ¿Por qué Locale Es_mx funciona pero no Es?

¿La definición de una expresión regular?

¿Por qué el documento principal Shell Here no funciona para el subcomando en Dash pero Bash funciona?

¿Por qué Tomcat funciona con el puerto 8080 pero no con el 80?

¿Por qué `\d` no funciona en expresiones regulares en sed?

wc -l NO cuenta lo último del archivo si no tiene un carácter de final de línea