Português (Brasil)

Ferramentas de texto e do dia a dia · Kit de ferramentas de texto

De Kleene a JavaScript: uma breve história das expressões regulares

· Fundo

expressões regulares javascript história da computação

Uma linha do tempo conectando autômatos finitos, Unix grep, Perl e expressões regulares JavaScript
Ilustração vetorial original ToolAcre

Rastreia expressões regulares da teoria dos autômatos dos anos 1950 por meio de ed, grep e Perl até o sabor JavaScript em cada navegador, explicando por que a sintaxe tem a aparência que tem e quais recursos chegaram quando.

A pequena e estranha linguagem que todo mundo conhece pela metade - por que a sintaxe regex parece antiga e inconsistente

As expressões regulares parecem uma linguagem montada ao longo das épocas porque é substancialmente isso que são. Um núcleo compacto de alternância, repetição e agrupamento cresceu da notação matemática para comandos de editor, filtros de linha de comando e recursos de linguagem de programação. A pontuação sobreviveu enquanto cada host acrescentava suas próprias conveniências, restrições e terminologia.

Essa história explica por que um padrão pode parecer familiar, mas se comportar de maneira diferente entre grep, Perl, Python e JavaScript. “Regex” é um nome de família, não uma gramática universal. Para um analista autodidata, a lição útil não é memorizar todos os dialetos, mas identificar o mecanismo, os sinalizadores e as regras de substituição antes de confiar em um padrão emprestado.

Os eventos regulares de Kleene - a matemática dos autômatos finitos da década de 1950 que nos deu a estrela

O trabalho de Stephen Cole Kleene sobre autômatos finitos e “eventos regulares” forneceu a raiz teórica durante a década de 1950. Sua notação descreveu conjuntos de sequências de símbolos usando operações incluindo união, concatenação e fechamento. A operação de fechamento tornou-se a estrela de Kleene: `A*` significa zero ou mais repetições extraídas de A, e não apenas “repetir uma ou mais”.

As linguagens regulares formais reconhecidas por autômatos finitos são mais restritas do que muitas construções hoje vendidas sob o rótulo regex. As referências anteriores, por exemplo, podem expressar condições além desse modelo clássico. Os motores modernos preservam, portanto, o nome histórico e grande parte da notação enquanto implementam linguagens de padrões cujas capacidades e estratégias de execução vão além do objeto matemático original de Kleene.

Thompson, ed e grep — como a regex entrou na edição de texto no final dos anos 1960 e início dos anos 1970 nas ferramentas Unix

Ken Thompson conectou a teoria às ferramentas de texto de trabalho. Seu artigo 1968 Communications of the ACM descreveu a compilação de expressões regulares em código de máquina para pesquisa de texto, e seu trabalho anterior como editor ajudou a colocar a correspondência de padrões dentro da linhagem Unix. O editor `ed` usou expressões regulares em comandos que selecionaram e transformaram linhas correspondentes.

O nome `grep` veio de um comando `ed` comumente renderizado como `g/re/p`: selecione globalmente as linhas que correspondem a uma expressão regular e imprima-as. O grep inicial não era a coleção atual de opções GNU, e os formulários POSIX básicos e estendidos posteriores são diferentes. A mudança duradoura foi prática: uma pequena linguagem simbólica tornou-se uma interface cotidiana para encontrar texto.

Perl e PCRE — as extensões que adicionaram quantificadores não gananciosos, lookaround e a sintaxe que a maioria das ferramentas copia hoje

Perl criou uma linguagem de padrões mais rica, central para a programação de uso geral. Em todas as suas versões, os programadores encontraram grupos de captura, referências anteriores, asserções, quantificadores preguiçosos e modificadores de padrão em um ecossistema altamente visível. A documentação 5 do Perl registra construções como `*?` para correspondência mínima e `(?=...)` para antecipação positiva, junto com muitos recursos ausentes em formulários Unix mais antigos.

É mais seguro dizer que Perl popularizou esse estilo do que creditar a ele a invenção de todas as extensões. PCRE ofereceu deliberadamente sintaxe compatível com Perl, enquanto outros motores adotaram ideias selecionadas e rejeitaram outras. A pontuação compartilhada pode ocultar diferentes semânticas, comportamento ou desempenho Unicode. Conseqüentemente, “semelhante a Perl” descreve uma ampla influência, não uma garantia de que um padrão Perl seja portátil.

Perl popularizou uma linguagem de padrões prática mais ampla; motores posteriores emprestados seletivamente

JavaScript padronizou seus próprios objetos `RegExp` e sintaxe literal, como `/pattern/gi`, para programas executados em navegadores e outros ambientes ECMAScript. Seu sabor inclui grupos de captura e não captura, referências anteriores, antecipação, quantificadores preguiçosos e classes de caracteres. Edições posteriores adicionaram grupos de captura nomeados e asserções lookbehind na especificação ES2018.

JavaScript não é PCRE ou Python com delimitadores diferentes. A disponibilidade dos recursos depende da edição ECMAScript implementada pelo mecanismo, e os sinalizadores fazem parte do comportamento e não da decoração. O guia de expressões regulares de MDN é a referência prática relevante para a sintaxe do navegador, mas mesmo exemplos válidos de JavaScript podem depender de sinalizadores que uma interface específica não expõe.

JavaScript ganhou grupos nomeados e lookbehind em ES2018, mas mecanismos e sinalizadores ainda diferem

Os navegadores colocam um mecanismo de expressão regular JavaScript próximo ao trabalho de texto comum. Uma página pode compilar um padrão, contar correspondências e passá-lo para `String.prototype.replace` sem enviar o texto para um serviço regex especializado. Essa disponibilidade torna possível uma interface de localizar e substituir no navegador, embora a página ao redor ainda deva ser inspecionada separadamente para reivindicações de privacidade mais amplas.

A implementação de ToolAcre chama `new RegExp` dentro de `compilePattern`, detecta falhas de compilação e retorna um erro em vez de lançar. `findReplace` conta as correspondências antes de aplicar a operação de substituição padrão. Como resultado, os tokens de substituição JavaScript, como referências de captura, seguem a sequência de host API; A sintaxe regex e a sintaxe de substituição são linguagens relacionadas, mas distintas.

O que isso não cobre - teoria formal da linguagem além do básico e aspectos internos do desempenho do motor

Esta curta história não prova equivalência entre motores práticos e autômatos finitos, algoritmos de execução de regex de pesquisa ou classificações de implementações por velocidade. Retrocesso, técnicas de tempo linear e padrões patológicos merecem tratamento separado. O guarda ToolAcre captura erros de sintaxe, mas não detecta uma expressão válida que executa retrocesso excessivo e paralisa o thread principal do navegador.

A linha do tempo também não atribui cada metacaractere a um único inventor. Os recursos de software geralmente chegavam por meio de artigos, editores, lançamentos de idiomas e reimplementações compatíveis, em vez de uma transferência limpa. As fontes apoiam marcos específicos; eles não justificam a história mais simples de que um produto criou regex moderno no atacado ou que sabores posteriores herdaram comportamento idêntico.

Conclusão: o modo regex do Text Toolkit é do tipo JavaScript, portanto, os padrões da documentação do navegador funcionam como estão escritos

A herança prática é visível em ToolAcre: ligue o Regex e o texto de pesquisa é compilado pelo mecanismo JavaScript do navegador. Deixe o Regex desativado e os metacaracteres serão escapados, tornando a pesquisa literal. A palavra inteira envolve a expressão com limites `` no estilo ASCII, enquanto a distinção entre maiúsculas e minúsculas controla se o sinalizador `i` acompanha o sinalizador global sempre presente `g`.

Esse último detalhe corrige a ampla promessa do esboço de que os padrões de documentação do navegador funcionam como estão escritos. ToolAcre não expõe sinalizadores multilinha, ponto-tudo, fixo ou Unicode, portanto, exemplos que exigem `m`, `s`, `y`, `u` ou `v` precisam de adaptação e alguns não podem ser reproduzidos lá. Use a ferramenta para testar padrões JavaScript suportados, ler a contagem de substituições e desfazer antes de refinar.