Español

Texto y herramientas cotidianas · Text Toolkit

De Kleene a JavaScript: una breve historia de las expresiones regulares

· Antecedentes

expresiones regulares javascript historial-de-computación

Una línea de tiempo que conecta autómatas finitos, grep de Unix, Perl y expresiones regulares de JavaScript
Ilustración de vector original de ToolAcre

Rastrea expresiones regulares desde la teoría de autómatas de la década de 1950 a través de ed, grep y Perl hasta el estilo JavaScript en cada navegador, explicando por qué la sintaxis se ve como se ve y qué características llegaron y cuándo.

El pequeño y extraño lenguaje que todo el mundo conoce a medias: por qué la sintaxis de expresiones regulares parece antigua e inconsistente

Las expresiones regulares se sienten como un lenguaje ensamblado a lo largo de épocas porque eso es sustancialmente lo que son. Un núcleo compacto de alternancia, repetición y agrupación creció desde la notación matemática hasta los comandos del editor, los filtros de la línea de comandos y las características del lenguaje de programación. La puntuación sobrevivió mientras cada anfitrión añadía sus propias comodidades, limitaciones y terminología.

Esa historia explica por qué un patrón puede parecer familiar pero comportarse de manera diferente entre grep, Perl, Python y JavaScript. "Regex" es un apellido, no una gramática universal. Para un analista autodidacta, la lección útil no es memorizar cada dialecto, sino identificar el motor, las banderas y las reglas de reemplazo antes de confiar en un patrón prestado.

Los eventos regulares de Kleene: las matemáticas de los autómatas finitos de la década de 1950 que nos dieron la estrella

El trabajo de Stephen Cole Kleene sobre autómatas finitos y “eventos regulares” proporcionó la raíz teórica durante la década de 1950. Su notación describía conjuntos de secuencias de símbolos utilizando operaciones que incluían unión, concatenación y cierre. La operación de cierre se convirtió en la estrella de Kleene: `A*` significa cero o más repeticiones extraídas de A, no simplemente “repetir una o más”.

Los lenguajes regulares formales reconocidos por los autómatas finitos son más limitados que muchas construcciones que ahora se venden bajo la etiqueta regex. Las referencias retrospectivas, por ejemplo, pueden expresar condiciones más allá de ese modelo clásico. Por lo tanto, los motores modernos conservan el nombre histórico y gran parte de la notación al tiempo que implementan lenguajes de patrones cuyas capacidades y estrategias de ejecución se extienden más allá del objeto matemático original de Kleene.

Thompson, ed y grep: cómo las expresiones regulares entraron en la edición de texto a finales de los 60 y principios de los 70 en las herramientas Unix

Ken Thompson conectó la teoría con las herramientas del texto de trabajo. Su artículo 1968 Communications of the ACM describía la compilación de expresiones regulares en código de máquina para buscar texto, y su trabajo anterior como editor ayudó a colocar la coincidencia de patrones dentro del linaje Unix. El editor `ed` utilizó expresiones regulares en comandos que seleccionaban y transformaban líneas coincidentes.

El nombre `grep` proviene de un comando `ed` comúnmente representado como `g/re/p`: seleccione globalmente líneas que coincidan con una expresión regular e imprímalas. Los primeros grep no eran la colección actual de opciones GNU, y las formas POSIX básicas y extendidas posteriores difieren. El cambio duradero fue práctico: un pequeño lenguaje simbólico se convirtió en una interfaz cotidiana para encontrar texto.

Perl y PCRE: las extensiones que agregaron cuantificadores no codiciosos, búsquedas y la sintaxis que la mayoría de las herramientas copian hoy

Perl hizo que un lenguaje de patrones más rico fuera central para la programación de propósito general. En todas sus versiones, los programadores encontraron grupos de captura, referencias retrospectivas, afirmaciones, cuantificadores perezosos y modificadores de patrones en un ecosistema altamente visible. La documentación de Perl 5 registra construcciones como `*?` para una coincidencia mínima y `(?=...)` para una anticipación positiva, junto con muchas características ausentes en las formas más antiguas de Unix.

Es más seguro decir que Perl popularizó este estilo que darle crédito por haber inventado cada extensión. PCRE ofreció deliberadamente una sintaxis compatible con Perl, mientras que otros motores adoptaron ideas seleccionadas y rechazaron otras. La puntuación compartida puede ocultar diferentes semánticas, comportamiento Unicode o rendimiento. En consecuencia, “similar a Perl” describe una influencia amplia, no una garantía de que un patrón Perl sea portátil.

Perl popularizó un lenguaje de patrones práctico más amplio; motores posteriores tomados prestados selectivamente

JavaScript estandarizó sus propios objetos `RegExp` y su sintaxis literal, como `/pattern/gi`, para programas que se ejecutan en navegadores y otros entornos ECMAScript. Su tipo incluye captura y no captura de grupos, referencias retrospectivas, anticipación, cuantificadores diferidos y clases de caracteres. Las ediciones posteriores agregaron grupos de captura con nombre y aserciones retrospectivas en la especificación ES2018.

JavaScript no es PCRE ni Python con delimitadores diferentes. La disponibilidad de funciones depende de la edición ECMAScript implementada por el motor, y las banderas son parte del comportamiento más que de decoración. La guía de expresiones regulares de MDN es la referencia práctica relevante para la sintaxis del navegador, pero incluso los ejemplos válidos de JavaScript pueden depender de indicadores que una interfaz particular no expone.

JavaScript obtuvo grupos con nombre y búsqueda retrospectiva en ES2018, pero los motores y las banderas aún difieren

Los navegadores colocan un motor de expresiones regulares de JavaScript cerca del trabajo de texto normal. Una página puede compilar un patrón, contar coincidencias y pasarlo a `String.prototype.replace` sin enviar el texto a un servicio de expresiones regulares especializado. Esa disponibilidad hace posible una interfaz de búsqueda y reemplazo en el lado del navegador, aunque la página circundante aún debe inspeccionarse por separado para reclamos de privacidad más amplios.

La implementación de ToolAcre llama a `new RegExp` dentro de `compilePattern`, detecta fallas de compilación y devuelve un error en lugar de generarlo. `findReplace` cuenta las coincidencias antes de aplicar la operación de reemplazo estándar. Como resultado, los tokens de reemplazo de JavaScript, como las referencias de captura, siguen la API de cadena del host; La sintaxis de expresiones regulares y la sintaxis de reemplazo son lenguajes relacionados pero distintos.

Lo que esto no cubre: teoría del lenguaje formal más allá de lo básico y aspectos internos del rendimiento del motor.

Esta breve historia no prueba la equivalencia entre motores prácticos y autómatas finitos, ni examina algoritmos de ejecución de expresiones regulares ni clasifica las implementaciones por velocidad. El retroceso, las técnicas de tiempo lineal y los patrones patológicos merecen un tratamiento aparte. La protección de ToolAcre detecta errores de sintaxis, pero no detecta una expresión válida que realiza un retroceso excesivo y detiene el hilo principal del navegador.

La línea de tiempo tampoco asigna cada metacarácter a un solo inventor. Las características del software a menudo llegaban a través de artículos, editores, versiones de idiomas y reimplementaciones compatibles en lugar de una transferencia limpia. Las fuentes respaldan hitos específicos; no justifican la historia más simple de que un producto creó expresiones regulares modernas al por mayor o que sabores posteriores heredaron un comportamiento idéntico.

La conclusión: el modo de expresión regular de Text Toolkit es el tipo JavaScript, por lo que los patrones de la documentación del navegador funcionan tal como están escritos.

La herencia práctica es visible en ToolAcre: active Regex y el motor JavaScript del navegador compila el texto de búsqueda. Si se deja desactivada Regex, se escapan los metacaracteres, lo que hace que la búsqueda sea literal. La palabra completa envuelve la expresión con límites `` de estilo ASCII, mientras que la distinción entre mayúsculas y minúsculas controla si el indicador `i` acompaña al indicador global `g` siempre presente.

Ese último detalle corrige la amplia promesa del esquema de que los patrones de documentación del navegador funcionan tal como están escritos. ToolAcre no expone indicadores multilínea, punto-todo, adhesivos o Unicode, por lo que los ejemplos que requieren `m`, `s`, `y`, `u` o `v` necesitan adaptación y algunos no se pueden reproducir allí. Utilice la herramienta para probar los patrones de JavaScript compatibles, leer el recuento de reemplazos y deshacerlos antes de refinarlos.