03 / GUIAS
Um fluxo seguro para testar expressões regulares
Um ciclo de escrever-testar-refatorar para expressões regulares em JavaScript: dados de amostra realistas, higiene contra backtracking catastrófico, disciplina de ancoragem, semântica de flags e por que testar no navegador mantém os padrões privados.
O ciclo: escrever, testar, refatorar
Uma regex confiável nunca é escrita numa única passada. Comece com o menor padrão que casa um exemplo real, execute-o, depois amplie ou aperte contra o próximo exemplo. O texto de amostra é a especificação; o padrão é a implementação.
Com a execução automática ativada, o teste roda pouco depois de você parar de digitar, não a cada tecla. Isso mantém rápido o ciclo de editar e testar.
- Comece de uma amostraEscreva o padrão contra uma amostra concreta, não de memória: cole uma linha real do log ou do documento que você pretende analisar.
- Teste cada ediçãoTeste após cada mudança — uma regex não tem avisos de compilador, então o único feedback é o que ela casa e o que ela deixa passar.
- Refatore para leitoresRefatore para leitura quando passar: grupos de captura nomeados e grupos de não captura tornam um padrão funcional sobrevivível para o próximo leitor.
Respeite o backtracking catastrófico
O motor de regex do JavaScript faz backtracking: quando um casamento falha, ele tenta de novo com comprimentos diferentes para cada quantificador. Quantificadores aninhados como (a+)+ sobre uma string de quase-casamento fazem a contagem de tentativas explodir exponencialmente — um padrão que responde instantaneamente com entrada boa pode rodar por anos com entrada ruim. Atacantes chamam isso de ReDoS.
JavaScript Regex Tester executa padrões em um Web Worker com orçamento de 650 milissegundos e informa quando há timeout. Se isso acontecer com dados realistas, teste o padrão no mecanismo e com os limites de entrada usados em produção.
- Quantificadores aninhadosA forma clássica é um grupo quantificado contendo um token quantificado — (a+)+, (\w+)* — em que muitas partições da mesma string satisfazem o padrão interno.
- Alternância ambíguaAlternância ambígua também provoca isso: (a|aa)+ dá ao motor duas formas de casar cada caractere extra, dobrando a árvore de busca por caractere.
- Correções estruturaisAs correções são estruturais: torne o casamento interno inequívoco, limite-o com limites de comprimento explícitos e sempre teste a entrada de quase-casamento, não só as válidas.
Ancore antes de confiar no casamento
Um padrão que encontra uma substring não é um padrão que valida um valor. /\d+/ casa dentro de abc123xyz; /^\d+$/ aceita apenas dígitos. A maioria dos bugs de validação são âncoras faltando, e a maioria dos bugs de extração são âncoras que não deveriam estar lá.
- Início e fim^ e $ fixam o casamento no início e no fim da string — ou de cada linha quando a flag multiline está ativa, o que muda silenciosamente o que «a entrada inteira» significa.
- Fronteiras de palavraFronteiras de palavra \b impedem que padrões curtos casem dentro de palavras mais longas: \bcat\b encontra o animal, não o cat em concatenate.
- Busca vs. validaçãoDecida busca versus validação desde o início: padrões de extração normalmente não querem âncoras, validadores quase sempre querem as duas.
Teste com dados de amostra realistas
Um padrão provado contra três exemplos arrumadinhos falha em produção no quarto real. Monte um conjunto de amostras que espelha a distribuição da entrada: o valor legítimo mais longo, a string vazia, variantes com espaços, nomes em Unicode e o quase-casamento que deveria quase casar, mas não pode.
- Quase-casamentosInclua o quase-casamento: um padrão de e-mail deve ser testado contra a@b e a b@c.d, não só contra endereços bem formados.
- UnicodeInclua nomes com acentos e outros dados Unicode: com u, o ponto consome pontos de código, mas \w não é uma classe geral de letras Unicode. Use uma propriedade como \p{L} quando necessário.
- Reexecute o conjuntoMantenha o conjunto de amostras ao lado do padrão; quando o padrão muda, reexecute o conjunto inteiro, não só o caso que motivou a mudança.
Flags mudam a linguagem, não só a busca
Flags fazem parte do significado do padrão. g decide se você obtém o primeiro casamento ou todos, i dobra maiúsculas e minúsculas, m reancora ^ e $ às linhas, s deixa o ponto cruzar quebras de linha e u coloca o motor em modo ciente de Unicode com sintaxe mais estrita.
O espaço de trabalho avalia o padrão com as flags que você seleciona e lista cada casamento com seus deslocamentos de início e fim, grupos de captura numerados e nomeados com suas próprias posições e uma prévia de substituição ao vivo — então uma mudança de flag aparece como diferença concreta no resultado, não como teoria.
- g e lastIndexSem g, test() e match() veem só a primeira ocorrência; com g, um objeto regex carrega o estado lastIndex que faz chamadas repetidas de test() alternarem resultados — um bug de produção famoso.
- s amplia o pontos (dotAll) faz . casar quebras de linha, o que pode silenciosamente ampliar o apetite de um padrão antigo quando ativado globalmente.
- u e amigosu habilita escapes atentos a Unicode e sintaxe mais estrita; não transforma \w nem \d em classes gerais de letras ou dígitos Unicode. O testador também aceita d, y e v.
Mantenha o padrão e as amostras locais
Dados de teste muitas vezes são dados reais: e-mails de clientes, linhas de log internas, identificadores de um relatório de incidente. Colá-los num testador hospedado os envia à infraestrutura de outra pessoa. Um testador no navegador mantém a sessão na aba — o padrão e o texto de amostra são avaliados pelo motor do seu próprio dispositivo e nunca transmitidos.
O runtime local é explícito sobre seus tetos: padrões de até 4.096 caracteres, texto de amostra de até 100.000 caracteres, substituições de até 20.000 e no máximo 1.000 casamentos relatados por execução. Esses limites são dimensionados para desenvolvimento e depuração; análise de logs em massa pertence a um script local, não a uma aba de navegador.
Copie para fora só o que você precisa — o padrão final e a string de substituição — e deixe os dados de amostra onde começaram: na sua máquina.
Teste um padrão localmenteDados extraídos costumam parar em JSON.
Quando um padrão extrai valores de texto bruto, inspecione e compare o payload resultante com uma rotina local determinística.