Quando você NÃO deve usar expressões regulares? [fechadas]

50

Expressões regulares são uma ferramenta poderosa no arsenal de programadores, mas - existem alguns casos em que não são a melhor opção ou são totalmente prejudiciais.

O exemplo simples nº 1 é analisar o HTML com o regexp - um caminho conhecido para vários bugs. Provavelmente, isso também atribui à análise em geral.

Mas existem outras áreas claramente proibidas para expressões regulares?


ps: " A pergunta que você está fazendo parece subjetiva e provavelmente será encerrada. " - portanto, quero enfatizar que estou interessado em exemplos em que o uso de regexps é conhecido por causar problemas.

c69
fonte
9
Analisar HTML com regexp não é apenas "um caminho conhecido para inúmeros erros". Na verdade é impossível .
Kramii Restabelece Monica
19
Não só é impossível, ele também leva a loucura e condenação eterna
Martin Wickman
3
@ Jörg: Regexp é apenas uma abreviação de expressão regular.
Joren
3
@ Jörg: É bem verdade que há uma enorme diferença entre expressões regulares em matemática e suas implementações em bibliotecas de software. Também é verdade que a maioria das bibliotecas de expressões regulares tem extensões que as colocam muito além de aceitar apenas linguagens regulares, e que chamá-las de expressões regulares nem sempre é tão apropriado. Concordo com você que existem dois conceitos diferentes. Mas eles têm o mesmo nome; regexp ainda é apenas uma abreviação, não um termo em si. Muitos desses exemplos neste site usam o termo completo para as bibliotecas de software.
Joren
2
@ Jörg - estas são semânticas. Embora possa ser uma boa idéia chamar esses padrões em nomes diferentes (mesmo que apenas para evitar a falácia de "expressões regulares são para idiomas regulares"), "regexp" / "expressões regulares" não é uma tentativa muito boa e leva apenas a confusão adicional.
Kobi

Respostas:

60

Não use expressões regulares:

  • Quando existem analisadores.

Isso não se limita ao HTML . Um XML válido simples não pode ser razoavelmente analisado com uma expressão regular, mesmo que você conheça o esquema e saiba que ele nunca será alterado.

Não tente, por exemplo, analisar o código fonte do C # . Analise-o para obter uma estrutura de árvore significativa ou os tokens.

  • De maneira mais geral, quando você tem ferramentas melhores para fazer seu trabalho.

E se você precisar procurar uma letra, pequena e maiúscula? Se você gosta de expressões regulares, você as usará. Mas não é mais fácil / rápido / legível usar duas pesquisas, uma após a outra? Provavelmente, na maioria dos idiomas, você obterá melhor desempenho e tornará seu código mais legível.

Por exemplo, o código de exemplo na resposta do Ingo é um bom exemplo quando você não deve usar expressões regulares. Basta procurar fooe depois bar.

  • Ao analisar a escrita humana.

Um bom exemplo é um filtro de obscenidade. Não é apenas uma má idéia, em geral, implementá-lo, mas você pode ser tentado a fazê-lo usando expressões regulares, e você o fará errado. Há muitas maneiras pelas quais um humano pode escrever uma palavra, um número, uma frase e será entendido por outro humano, mas não pela sua expressão regular. Então, em vez de capturar uma verdadeira obscenidade, sua expressão regular passará o tempo dela prejudicando outros usuários.

  • Ao validar alguns tipos de dados.

Por exemplo, não valide um endereço de email por meio de uma expressão regular. Na maioria dos casos, você fará errado. Em um caso raro, você fará tudo certo e terminará com um horror de codificação de 6 343 caracteres .

Sem as ferramentas certas, você cometerá erros. E você os notará no último momento, ou talvez nunca. Se você não se importa com código limpo, escreverá uma sequência de vinte linhas sem comentários, sem espaços, sem novas linhas.

  • Quando o seu código será lido. E então leia novamente, e novamente e novamente, sempre, por diferentes desenvolvedores.

Sério, se eu pegar o seu código e precisar revisá-lo ou modificá-lo, não quero passar uma semana tentando entender uma sequência de vinte linhas com muitos símbolos.

Arseni Mourzenko
fonte
9
"Sério, se eu pegar seu código e precisar revisá-lo ou modificá-lo, não quero passar uma semana tentando entender uma sequência de vinte linhas com vários símbolos". +1!
funkybro
11
Esta é uma resposta muito melhor do que sua irmã passo sobre estouro de pilha: stackoverflow.com/questions/7553722/...
Kobi
11
Se você estiver usando Perl / PCRE (e provavelmente também os outros sabores modernos de regex), leia sobre sub-rotinas, denominadas grupos de captura e (?(DEFINE))asserções;) muito semelhante ao que você escreveria em yacc ou equivalente;)
Nikić
2
O uso de expressões regulares para analisar as palavras da lista negra é um erro clututivo.
Dan Ray
Não há nenhuma razão no mundo para evitar jogar um regex em uma string como "<a href='foo'>stuff</a>". Regexes modernos não têm problemas com isso.
precisa saber é
18

O mais importante: quando o idioma que você está analisando não é regular .

O HTML não é uma linguagem comum e não é possível analisá-lo com uma expressão regular (não apenas difícil ou um caminho para o código de buggy).

Matteo
fonte
4
Errado! Se você estiver usando qualquer um dos sabores modernos de regex (Perl, PCRE, Java, .NET, ...), poderá fazer recursão e asserções e, portanto, analisar também corresponderá a gramáticas livres de contexto e sensíveis ao contexto.
NikiC 9/10
9
@NikiC. Não está errado. "Modern regex flavors" não são expressões regulares (que podem ser usadas para analisar idiomas regulares, daí o nome). Concordo que com o PRE você pode fazer mais, mas eu não os chamaria apenas de "expressões regulares" (como na pergunta original).
Matteo
11
As expressões regulares modernas estão muito além do que sua avó ensinou que as expressões regulares poderiam fazer, e que o conselho dela é irrelevante. E até as expressões regulares primitivas podem lidar com a maioria dos pequenos trechos de HTML. Essa proibição geral é ridícula e irrealista. Regexes foram feitos para esse tipo de coisa. E sim, eu sei do que estou falando .
tchrist
12

No stackoverflow, muitas vezes vemos pessoas solicitarem expressões regulares que descubram se uma determinada string não contém isto ou aquilo. Isto é, IMHO, invertendo o objetivo da expressão regular. Mesmo que exista uma solução (empregando asserções negativas por trás do objeto ou algo assim), muitas vezes é muito melhor usar o regex para o que foi feito e lidar com o caso negativo com a lógica do programa.

Exemplo:

# bad
if (/complicated regex that assures the string does NOT conatin foo|bar/) {
    # do something
}

# appropriate
if (/foo|bar/) {
    # error handling
} else {
    # do something
}
Ingo
fonte
11
+1: algumas vezes, evitei me codificar em um canto com expressões regulares parando e me perguntando "Ok, com o que estou tentando corresponder especificamente?" em vez de "O que estou tentando evitar?"
5

Dois casos:

Quando existe uma maneira mais fácil

  • A maioria dos idiomas fornece uma função simples como INSTR para determinar se uma sequência é um subconjunto de outra. Se é isso que você deseja fazer, use a função mais simples. Não escreva sua própria expressão regular.

  • Se houver uma biblioteca disponível para executar uma manipulação complexa de cadeias, use-a em vez de escrever sua própria expressão regular.

Quando expressões regulares não são suficientemente poderosas

  • Se você precisar de um analisador, use um analisador.
Kramii Restabelecer Monica
fonte
0

Expressões regulares não podem identificar estruturas recursivas . Essa é a limitação fundamental.

Pegue o JSON - é um formato bastante simples, mas como um objeto pode conter outros objetos como valores de membros (arbitrariamente profundos), a sintaxe é recursiva e não pode ser analisada por uma regex. Por outro lado, o CSV pode ser analisado por expressões regulares, uma vez que não contém estruturas recursivas.

Em resumo, expressões regulares não permitem que o padrão se refira a si próprio. Você não pode dizer: neste ponto da sintaxe, corresponda a todo o padrão novamente. Dito de outra forma, as expressões regulares correspondem apenas linearmente, não contém uma pilha que permita acompanhar a profundidade de um padrão aninhado.

Observe que não tem nada a ver com a complexidade ou complexidade do formato. As expressões S são realmente muito simples, mas não podem ser analisadas com uma regex. CSS2, por outro lado, é uma linguagem bastante complexa, mas não contém estruturas recursivas e, portanto, pode ser analisada com um regex. (Embora isso não seja verdade para CSS3 devido a expressões CSS, que possuem uma sintaxe recursiva.)

Portanto, não é porque é feio ou complexo ou propenso a erros analisar o HTML usando apenas regex. É que simplesmente não é possível .

Se você precisar analisar um formato que contenha estruturas recursivas, precisará pelo menos complementar o uso de expressões regulares com uma pilha para acompanhar o nível de estruturas recursivas. Normalmente, é assim que um analisador funciona. Expressões regulares são usadas para reconhecer as partes "lineares", enquanto o código personalizado fora da regex é usado para acompanhar as estruturas aninhadas.

Normalmente, a análise como essa é dividida em fases separadas. Tokenização é a primeira fase em que expressões regulares são usadas para dividir a entrada em uma sequência de "tokens", como palavras, pontuação, colchetes, etc. A análise é a próxima fase em que esses tokens são analisados ​​em uma estrutura hierárquica, uma árvore de sintaxe.

Portanto, quando você ouvir que HTML ou C # não podem ser analisados ​​por expressões regulares, lembre-se de que expressões regulares ainda são uma parte crítica dos analisadores. Você simplesmente não pode analisar esse idioma usando apenas expressões regulares e nenhum código auxiliar.

JacquesB
fonte