El carácter "$" en Regex no significa "fin de cadena"

Disputa central: qué significa $

  • El hilo gira en torno al hecho de que, en muchos motores, $ en modo no multilinea coincide con el final de la cadena o justo antes de un \n final, no estrictamente con el “fin de la cadena”.
  • Algunos motores (JS, Go, Rust, estilo RE2) hacen que $ sea equivalente a “fin de cadena” cuando multilinea está desactivado.
  • Otros (Python, Java, C#, PHP, Perl, PCRE, etc.) tratan $ más como “fin de línea”, con un caso especial para un único salto de línea final.
  • Varios comentaristas encuentran sorprendente y “whacky” el comportamiento de estilo Python/Perl, especialmente ejemplos como que cat$ no coincida con cat\n\n.

Semántica de línea frente a cadena

  • Un gran subhilo debate si $ es conceptualmente “fin de línea” o “fin de cadena”.
  • Un lado insiste en que la visión histórica, basada en líneas (de editores, ed/sed/grep), justifica que $ trate de forma especial un salto de línea final.
  • El otro lado replica que la mayoría de las APIs toman cadenas arbitrarias, no líneas, así que es razonable que los usuarios esperen que $ signifique “fin de cadena”.
  • Hay debate sobre las definiciones POSIX de “línea”, “línea incompleta” y sobre cómo un salto de línea como terminador frente a separador debería afectar a $.

Dialectos de regex y (falta de) estandarización

  • Muchos señalan que no existe un único estándar de regex; hay múltiples familias:
    • POSIX BRE/ERE, con semánticas distintas para los anclajes.
    • Perl/PCRE y descendientes (PHP, muchos lenguajes, PCRE2).
    • Estilo RE2, usado por Go y la crate regex de Rust, que evita deliberadamente algunas rarezas de Perl.
    • Regex de JavaScript ECMA, con sus propias lagunas y características.
  • Se mencionan C++ <regex>, ECMA-262, POSIX y un RFC reciente (I-Regexp) como especificaciones formales, pero coexisten en lugar de unificar el comportamiento.

Implicaciones de seguridad y corrección

  • Que $ coincida antes de un salto de línea final ha provocado errores reales, por ejemplo en validación de entrada en Ruby y en vulnerabilidades de ExifTool/GitLab, donde atacantes introducen payloads tras un salto de línea.
  • Recomendación de varios comentarios: cuando realmente quieras “cadena completa”, usa \A...\Z o \z donde estén disponibles, no ^...$.

Herramientas, patrones de uso y ergonomía

  • Muchos aconsejan comprobar siempre la documentación del motor concreto y probar las regex explícitamente.
  • Algunos prefieren herramientas orientadas a líneas (grep/sed/awk, editores como Vim) y piensan en términos de líneas; otros trabajan principalmente con cadenas en memoria y esperan semántica de cadena.
  • También aparece frustración más amplia por la fragmentación de sabores de regex, las reglas de escape y el soporte inconsistente para clases de caracteres y anclajes.