Após a interrupção do StackOverflow de ontem - a correspondência de expressões regulares é realmente difícil ou a implementação é simplesmente ineficiente?


8

Ontem, o StackOverflow ficou inoperante por meia hora. Mais tarde, eles escreveram um post sobre o assunto , detalhando que o problema surgiu da inesperadamente alta complexidade da correspondência de expressões regulares.

Em resumo, a expressão regular a+b, quando executada na string aaaaaaaaaaaaaac, é executada emO(n2) hora em que né o número de acaracteres, porque usa retrocesso.

Você pode reproduzir o problema com o seguinte código Python, que no meu computador leva mais de 4 segundos para ser executado:

import re, time
start = time.time()
re.findall(r'\s+$', ' '*20000 + 'x')
print(time.time() - start)

Isso foi muito surpreendente para mim; Eu pensaria que um par de regex funciona de maneira mais eficiente, por exemplo, construindo um DFA a partir do regex e executando a string desejada através dele, o que eu pensaria que seriaO(n) (não incluindo a construção do DFA).

(Por exemplo, o livro Introdução aos algoritmos de Cormen, Leiserson, Rivest passa por um algoritmo semelhante no caminho da introdução do algoritmo de Knuth-Morris-Pratt).

Minha pergunta: Existe algo inerentemente difícil na correspondência de expressões regulares que não permita umaO(n)algoritmo , ou estamos simplesmente falando de uma implementação ineficiente (em Python, em qualquer que seja o StackOverflow, etc.)?


2
Há um artigo sobre isso. Eu acho que está aqui, mas o servidor está inoperante no momento da escrita. O resumo executivo é que, sim, se você está apenas fazendo expressões regulares literais como a que causou o problema aqui, é possível combinar em tempo linear compilando um autômato, porém, para idiomas interpretados, é necessário considerar o tempo a compilação leva e se realmente vale a pena fazer isso.
precisa saber é o seguinte

Esse regex pode ser reescrito para se tornar mais rápido? Quero dizer, realmente tem que ir para funções de substr ou ele pode apenas pensar em melhor regex? Eu estou falando exatamente sobre este / \ s + $ / on ("" * 20000) + "x"
Nakilon

Respostas:


8

Se você apenas quisesse analisar expressões regulares, não teria esses problemas (a menos que fosse um programador realmente incompetente, eu acho). Advertências incluem o tempo necessário para construir um autômato; um algoritmo assintoticamente pior pode superar a abordagem do autômato em muitos casos na prática.

O problema real é provavelmente que eles usam funções de biblioteca que lidam com regexps, que são muito mais poderosos do que expressões regulares comuns. Além disso, recursos como grupos correspondentes introduzem mais complexidade.

Nesse caso, surgiram problemas porque esses mecanismos correspondem a substrings (com expressões regulares simples, normalmente correspondemos apenas a entradas inteiras) e usamos retrocesso ; correspondências parciais longas que, eventualmente, não correspondem, causam retornos longos. Em essência, esse é o pior caso para a correspondência ingênua de seqüência de caracteres em tempo quadrático.

Isso pode ser melhorado? Talvez. Usando as idéias dos autômatos de correspondência de cadeias , voltaríamos não para o segundo símbolo, mas para o início do sufixo mais longo que corresponde a um prefixo do padrão. Mas como o padrão não é mais fixo, certamente não é trivial estender as idéias.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.