3 puntos por GN⁺ 14 시간 전 | 1 comentarios | Compartir por WhatsApp
  • Las expresiones regulares tienen funciones y sintaxis distintas según la implementación, por lo que un patrón que funcionaba en una herramienta puede fallar o requerir modificaciones en otro entorno
  • Mientras más acostumbrado estés a entornos con muchas funciones, como Perl, más seguido te toparás con problemas de compatibilidad; y si además consideras computadoras donde no tienes permiso para instalar software, es más seguro usar un subconjunto común
  • Si se define “en cualquier lugar” de la forma más estricta, el alcance se reduce tanto que prácticamente solo quedan literales, clases de caracteres […] y caracteres especiales básicos como . * ^ $
  • Si usas GNU sed, awk, grep junto con la opción -E en sed y grep, se amplía el conjunto común de funciones disponibles, pero en esta combinación awk suele ser el mínimo común denominador
  • Emacs requiere barras invertidas para +? ( ) { } | y el significado de \s, \S también es distinto, así que para usar la misma expresión regular en varias herramientas hay que revisar incluso las sintaxis excepcionales

Por qué es difícil la compatibilidad de las expresiones regulares

  • La mayor incomodidad de las expresiones regulares proviene de las diferencias entre implementaciones
    • Una función disponible en una herramienta puede no existir en otra
    • Incluso la misma función puede tener una sintaxis ligeramente distinta
  • Perl es un entorno de expresiones regulares con muchas funciones, así que algo que parece obvio tomando Perl como referencia puede faltar en otros entornos
  • También se pueden usar reemplazos similares a Perl para otras herramientas, pero no son estándar, lo que dificulta enviar a colegas o clientes código que puedan ejecutar de inmediato
  • Si además se consideran situaciones en las que hay que trabajar en computadoras donde no se puede instalar software, hace falta un enfoque que busque un subconjunto de funciones de expresiones regulares que funcione en varios entornos
  • Mientras más estricta sea la definición de “en cualquier lugar”, menos funciones se pueden usar
    • Literales
    • Clases de caracteres […]
    • Caracteres especiales . * ^ $

Alcance común en sed, awk, grep y Emacs

  • Si se limita el conjunto de herramientas objetivo a sed, awk, grep y Emacs, el criterio de “en cualquier lugar” puede relajarse un poco
  • Al usar las versiones GNU de sed, awk, grep y aplicar la opción -E a sed y grep, la lista de funciones comunes se amplía
    • Las funciones de expresiones regulares de las tres herramientas son parecidas
    • Las funciones de awk también suelen estar disponibles en las otras herramientas
    • Como excepción, los límites de palabra en awk usan \<, \>, y son distintos de \b, \B
  • Emacs corresponde a la mayoría de las funciones de awk, pero tiene diferencias de sintaxis
    • Para que + ? ( ) { } | cumplan el mismo rol que en awk, necesitan una barra invertida antes
    • Las expresiones equivalentes a \s, \S de awk en Emacs son \s-, \S-
  • En Emacs, \s, \S no significan espacio/no espacio, sino que inician una clase de caracteres
    • La clase - significa espacio
    • \s. es un carácter de puntuación
    • \S. es un carácter que no es de puntuación
  • Con este criterio, las funciones que se pueden usar son las siguientes
    • .
    • ^, $
    • […], [^…]
    • *
    • \w, \W, \s, \S
    • Referencias inversas de \1 a \9
    • \b, \B
    • ?, +
    • Alternativas con |
    • Repetición {n,m}
    • Captura (...)
  • Sin embargo, gawk admite referencias inversas en las cadenas de reemplazo, pero no en la expresión regular en sí
  • look-around puede considerarse una función avanzada, y \d puede parecer una función básica para dígitos, pero muchas variantes de expresiones regulares no lo admiten

1 comentarios

 
Opiniones en Hacker News
  • En Emacs se sufre especialmente porque casi se siente como adivinar qué hay que escapar
    Existe una alternativa llamada rx[0], pero en la práctica no es agradable de usar
    Más allá de la sintaxis de las expresiones regulares en sí, en la etapa de uso real también aparecen a menudo problemas de codificación y escape
    Si ingresas una expresión regular en el shell, tienes que escaparla correctamente; en Python, debes asegurarte de que sea una cadena raw, y así
    Aun así, que la forma de usar expresiones regulares en la mayoría de las herramientas haya convergido dentro de un rango más o menos parecido es casi un milagro moderno
    [0]: https://www.gnu.org/software/emacs/manual/html_node/elisp/Rx...

    • Se vuelve más divertido cuando escribes Python que genera scripts de shell con expresiones regulares
      Siguen apareciendo situaciones en las que se superponen reglas de escape distintas
    • Si hubiera que buscarle una ventaja a la fuerza, cuando el objetivo de búsqueda es código Elisp, que ( y ) coincidan literalmente resulta un poco cómodo
    • Las expresiones regulares deberían haber sido un lenguaje estructurado, no una mezcolanza de varias DSL
  • El autor parece estar a punto de decirlo, sin terminar de llegar: al final, las expresiones regulares básicas de POSIX funcionan en todas partes
    Aunque con la salvedad de que no todos se han puesto al día con la edición 8 de Single Unix Specification, y que en esa edición las BRE cambiaron un poco

    • Esa valoración no me parece justa con el autor
      Si no hubiera existido esa salvedad, para empezar no habría hecho falta escribir ese artículo
  • Hace tiempo escribí un paper sobre encontrar expresiones regulares que hagan match de la misma manera tanto bajo semántica codiciosa como bajo semántica leftmost maximal
    https://par.nsf.gov/servlets/purl/10534654

  • Siempre he sido exigente con dejar claro qué lenguaje de expresiones regulares acepta cada herramienta, y qué es lo que hace match: cualquier subcadena, prefijo, sufijo, la cadena completa, una línea o una subcadena dentro de una línea
    Aquí están [los más usados][1], y además están PCRE y Python
    Me tomó un tiempo aprender que algunos de los formatos antiguos que se ven en lugares como grep [están especificados en POSIX][2]
    [1]: https://cppreference.com/cpp/regex#Regular_expression_gramma...
    [2]: https://pubs.opengroup.org/onlinepubs/009696899/basedefs/xbd...

  • Quiero compartir la página de Russ Cox sobre expresiones regulares
    Me parece un buen recurso para leer
    https://swtch.com/~rsc/regexp/

  • Por razones como estas es importante RFC 9485, I-Regexp: An Interoperable Regular Expression Format
    https://datatracker.ietf.org/doc/html/rfc9485

  • El paquete regexp de la biblioteca estándar de Go usa el motor RE2, por eso no admite referencias inversas
    Se pueden usar en sustituciones, pero no en matching

    • regexp no usa re2; es una implementación separada de los mismos conceptos
  • Después de sufrir frustraciones similares con motores de reglas, motores de plantillas y motores tipo IFTTT, hice una biblioteca en Rust para JSONLogic y también uso bindings para otros lenguajes
    https://github.com/GoPlasmatic/datalogic-rs

  • La documentación de JSON Schema también incluye un subconjunto recomendado de expresiones regulares
    https://json-schema.org/understanding-json-schema/reference/...