On the Complexity of the Matching Problem of Regular Expressions with Backreferences
Este artigo estabelece a complexidade computacional de granularidade fina da correspondência de expressões regulares com referências retroativas, provando limites inferiores condicionais sob as suposições de SETH e detecção de triângulos, ao mesmo tempo que apresenta um algoritmo aprimorado de para referências retroativas de uso único.
Artigo original sob licença CC BY 4.0 (http://creativecommons.org/licenses/by/4.0/). Esta é uma explicação gerada por IA do artigo abaixo. Não foi escrita nem endossada pelos autores. Para precisão técnica, consulte o artigo original. Ler aviso legal completo
O Panorama Geral: O Engarrafamento do "Regex"
Imagine que você é um guarda de segurança em um clube (o sistema de computador). Você tem uma lista de regras (uma Expressão Regular) sobre quem pode entrar.
- Regras Simples: "Apenas pessoas usando camisas vermelhas." Isso é fácil de verificar. Você olha para a camisa, diz "Vermelha? Sim, entre." Leva a mesma quantidade de tempo, seja a fila de 10 pessoas ou 10.000.
- O Problema (ReDoS): Às vezes, hackers criam uma fila específica de pessoas que engana o guarda, fazendo-o realizar uma quantidade massiva de trabalho desnecessário. Em vez de verificar uma pessoa e seguir em frente, o guarda começa a verificar a Pessoa A, depois a Pessoa B, depois a Pessoa A novamente, depois a Pessoa C, depois a Pessoa A novamente... até que o guarda colapse de exaustão. Isso é chamado de ataque de Negação de Serviço (ReDoS).
No mundo real, isso causou a queda de grandes sites como Stack Overflow e Cloudflare. O artigo observa que até mesmo uma lentidão "quadrática" (onde verificar 100 pessoas leva 10.000 passos) é suficiente para derrubar um sistema.
O Vilão: "Backreferences" (Referências Traseiras)
Regras padrão são simples. Mas os motores modernos de "Regex" têm um recurso superpoderoso chamado Backreferences.
A Analogia:
Imagine uma regra que diz: "Encontre uma palavra, lembre-se dela e, em seguida, garanta que a exata mesma palavra apareça novamente mais tarde."
- Exemplo: "Encontre uma palavra, chame-a de 'X'. Depois, encontre 'X' novamente."
- Se a entrada for
maçã ... maçã, funciona. - Se a entrada for
maçã ... banana, falha.
Esse recurso é incrivelmente útil para programadores, mas torna o trabalho do "guarda" muito mais difícil. O guarda precisa lembrar o que viu anteriormente e comparar constantemente com o que está vendo agora. O artigo pergunta: Podemos construir um guarda que seja rápido o suficiente para lidar com essas regras complexas sem ficar cansado?
As Descobertas do Artigo: O Bom, o Mau e o Feio
Os autores investigaram exatamente quão difícil é resolver esses problemas de correspondência. Eles dividiram em dois lados: Dificuldade (Por que é difícil) e Algoritmos (Como resolver).
1. A Má Notícia: Algumas Regras são Impossíveis de Acelerar
O artigo prova que, para certos tipos de regras complexas, não há "bala de prata" para torná-las rápidas.
- O Problema do "Triângulo": Eles mostraram que, se você tiver uma regra que usa duas variáveis (como lembrar duas palavras diferentes e verificá-las mais tarde), resolvê-la é tão difícil quanto encontrar um triângulo em um gráfico gigante de rede social. Se você pudesse resolver a regra rapidamente, poderia resolver o problema do gráfico rapidamente. Como especialistas em gráficos acreditam que o problema do gráfico é inerentemente lento, o problema da regra também deve ser lento.
- O Problema dos "Vetores Ortogonais": Para regras com ainda mais variáveis, eles provaram que o tempo necessário cresce exponencialmente com o número de variáveis. É como tentar encontrar uma combinação específica de chaves em uma fechadura; quanto mais chaves você tem, mais impossível se torna forçá-la rapidamente.
Conclusão: Se sua regra for muito complexa (usando muitos recursos de "lembre-se disto"), você não poderá construir um motor rápido para ela. Você sempre encontrará um muro.
2. A Boa Notícia: Uma Solução "Quase Linear" para Casos Simples
No entanto, o artigo encontrou um ponto ideal. Eles focaram em um tipo específico e comum de regra:
- O Padrão "ABCBD": "Encontre uma palavra (A), depois uma palavra (B), depois uma palavra (C), depois a exata mesma palavra B novamente, depois uma palavra (D)."
- Exemplo do mundo real: "Encontre um nome de usuário, depois uma senha, depois uma mensagem, depois o mesmo nome de usuário novamente, depois uma assinatura."
Os autores descobriram que, embora isso pareça complicado, pode ser resolvido com muita eficiência.
- O Jeito Antigo: Métodos anteriores eram como verificar todas as combinações possíveis em uma biblioteca, o que levava tempo (quadrático). Se o livro tivesse 1.000 páginas, levaria 1.000.000 de passos.
- O Novo Jeito: Os autores construíram um novo algoritmo que leva aproximadamente tempo.
- A Analogia: Imagine que a biblioteca está organizada com um sistema de índice mágico (usando Árvores de Sufixo e Florestas de Fatoração). Em vez de ler cada página, o guarda pode pular diretamente para as seções relevantes. Se o livro tiver 1.000 páginas, o novo método leva aproximadamente 10.000 passos (ou até menos), o que é uma melhoria massiva.
Como o Novo Algoritmo Funciona (Os "Truques de Mágica")
Para alcançar essa velocidade, os autores usaram várias técnicas inteligentes, que eles descrevem no artigo:
- A Árvore de Sufixo (O Mapa): Eles construíram um mapa gigante da string de entrada. Este mapa mostra todas as terminações possíveis da string. Ajuda o guarda a ver instantaneamente: "Ah, esta palavra 'B' aparece aqui, e também aparece ali."
- Decomposição Pesada-Leve (O Chapéu Seletor): Eles dividiram o mapa em caminhos "pesados" (caminhos muito comuns) e caminhos "leves" (caminhos raros). Eles só fazem o trabalho pesado nos caminhos raros, economizando tempo.
- Periodicidade (O Ritmo): Eles notaram que, quando uma palavra se repete (como "B...B"), a string frequentemente tem um ritmo ou um padrão. Eles usaram matemática para prever esses padrões em vez de verificar cada letra individualmente.
- Florestas de Fatoração (O Índice): Esta é uma estrutura de dados que atua como um índice super-rápido, permitindo que o guarda verifique se um trecho de texto corresponde a uma regra em tempo constante, não importa o tamanho do texto.
Resumo da Conclusão
- Podemos parar todos os ataques ReDoS? Não. Se uma regra for muito complexa (demasiadas variáveis de "lembre-se disto"), está matematicamente provado que será lenta.
- Podemos consertar as regras complexas mais comuns? Sim! Para o caso específico em que uma regra lembra uma palavra e a verifica uma vez mais tarde (o padrão "ABCBD"), os autores criaram um novo motor que é quase tão rápido quanto as regras simples.
- Por que isso importa? Isso diz aos engenheiros de software: "Não use muitos backreferences, ou você ficará lento. Mas se você os usar dessa maneira específica e comum, agora pode usar nosso novo método para manter seu sistema seguro e rápido."
O artigo essencialmente traça uma linha na areia: Aqui é onde o limite de velocidade é inquebrável, e aqui é onde encontramos uma maneira de dirigir mais rápido.
Afogado em artigos na sua área?
Receba digests diários dos artigos mais recentes que correspondam às suas palavras-chave de pesquisa — com resumos técnicos, no seu idioma.