Há uma citação popular de Jamie Zawinski :
Algumas pessoas, quando confrontadas com um problema, pensam "eu sei, vou usar expressões regulares". Agora eles tem dois problemas.
Como essa citação deve ser entendida?
Há uma citação popular de Jamie Zawinski :
Algumas pessoas, quando confrontadas com um problema, pensam "eu sei, vou usar expressões regulares". Agora eles tem dois problemas.
Como essa citação deve ser entendida?
Respostas:
Algumas tecnologias de programação geralmente não são bem compreendidas pelos programadores ( expressões regulares , ponto flutuante , Perl , AWK , IoC ... e outras ).
Essas podem ser ferramentas incrivelmente poderosas para resolver o conjunto certo de problemas. Expressões regulares, em particular, são muito úteis para combinar idiomas regulares. E existe o cerne do problema: poucas pessoas sabem como descrever uma linguagem comum (faz parte da teoria / linguística da ciência da computação que usa símbolos engraçados - você pode ler sobre isso na hierarquia de Chomsky ).
Ao lidar com essas coisas, se você as usar incorretamente, é improvável que você tenha realmente resolvido o seu problema original. Usando uma expressão regular para corresponder HTML (uma ocorrência muito comum) significa que você vai perder casos extremos. E agora, você ainda tem o problema original que não resolveu, e outro bug sutil flutuando foi introduzido usando a solução errada.
Isso não quer dizer que expressões regulares não devam ser usadas, mas que se deve trabalhar para entender qual o conjunto de problemas que eles podem resolver e não podem resolver e usá-los criteriosamente.
A chave para manter o software é escrever código de manutenção. O uso de expressões regulares pode ser contrário a esse objetivo. Ao trabalhar com expressões regulares, você escreveu um mini computador (especificamente um autômato de estado finito não determinístico ) em uma linguagem específica de domínio especial. É fácil escrever o equivalente do 'Hello world' nesse idioma e obter uma confiança rudimentar nele, mas é necessário ir mais além com o entendimento do idioma comum para evitar a gravação de erros adicionais que podem ser muito difíceis de identificar e corrigir (porque eles não fazem parte do programa em que a expressão regular está)
Então agora você tem um novo problema; você escolheu a ferramenta da expressão regular para resolvê-la (quando é inapropriada) e agora tem dois bugs, os quais são mais difíceis de encontrar, porque estão ocultos em outra camada de abstração.
Expressões regulares - particularmente expressões não triviais - são potencialmente difíceis de codificar, entender e manter. Você só precisa observar o número de perguntas no Stack Overflow marcadas [regex]
onde o questionador assumiu que a resposta para o problema é uma regex e, posteriormente, ficou paralisado. Em muitos casos, o problema pode (e talvez deva) ser resolvido de uma maneira diferente.
Isso significa que, se você decidir usar uma regex, agora terá dois problemas:
Basicamente, acho que ele quer dizer que você só deve usar um regex se não houver outra maneira de resolver seu problema. Outra solução provavelmente será mais fácil de codificar, manter e dar suporte. Pode ser mais lento ou menos eficiente, mas se isso não for crítico, a facilidade de manutenção e suporte deve ser a principal preocupação.
É principalmente uma piada explícita, embora com um pouco de verdade.
Existem algumas tarefas para as quais expressões regulares são um excelente ajuste. Certa vez, substituí 500 linhas de código do analisador de descida recursiva escrito manualmente por uma expressão regular que levou cerca de 10 minutos para depurar completamente. As pessoas dizem que as expressões regulares são difíceis de entender e depurar, mas as aplicadas adequadamente não são tão difíceis de depurar quanto um enorme analisador manual. No meu exemplo, demorou duas semanas para depurar todos os casos extremos da solução não regex.
No entanto, para parafrasear o tio Ben:
Com grande expressividade vem uma grande responsabilidade.
Em outras palavras, as expressões regulares acrescentam expressividade ao seu idioma, mas isso coloca mais responsabilidade no programador para escolher o modo de expressão mais legível para uma determinada tarefa.
Algumas coisas inicialmente parecem uma boa tarefa para expressões regulares, mas não são. Por exemplo, qualquer coisa com tokens aninhados, como HTML. Às vezes, as pessoas usam uma expressão regular quando um método mais simples é mais claro. Por exemplo, string.endsWith("ing")
é mais fácil entender do que o regex equivalente. Às vezes, as pessoas tentam colocar um grande problema em um único regex, onde é mais apropriado quebrá-lo em pedaços. Às vezes, as pessoas deixam de criar abstrações apropriadas, repetindo uma regex repetidamente, em vez de criar uma função bem nomeada para realizar o mesmo trabalho (talvez implementado internamente com uma regex).
Por alguma razão, as expressões regulares têm uma tendência estranha de criar um ponto cego para os princípios normais de engenharia de software, como responsabilidade única e DRY. É por isso que até as pessoas que os amam as consideram problemáticas às vezes.
Jeff Atwood traz uma interpretação diferente em um post do blog que discute esta citação: Expressões regulares: agora você tem dois problemas (obrigado a Euphoric pelo link)
Analisando o texto completo das postagens de Jamie no tópico original de 1997, encontramos o seguinte:
A natureza de Perl encoraja o uso de expressões regulares quase à exclusão de todas as outras técnicas; eles são, de longe, a maneira mais "óbvia" (pelo menos para as pessoas que não conhecem melhor) o caminho do ponto A ao ponto B.
A primeira citação é muito superficial para ser levada a sério. Mas eu concordo totalmente com isso. Aqui está o ponto que Jamie estava tentando enfatizar: não que expressões regulares sejam más, por si só, mas que o uso excessivo de expressões regulares seja ruim.
Mesmo se você não compreender totalmente as expressões regulares, você corre em The Golden Martelo problema, tentando resolver um problema com expressões regulares, quando teria sido mais fácil e mais clara para fazer a mesma coisa com o código normal (ver também CodingHorror: use Regex vs. abuso de Regex ).
Há outra postagem no blog que analisa o contexto da citação e entra em mais detalhes do que Atwood: Jeffrey Friedl's Blog: Fonte da famosa citação "Agora você tem dois problemas"
Há algumas coisas acontecendo com esta citação.
A citação é uma reafirmação de uma piada anterior:
Sempre que se depara com um problema, algumas pessoas dizem "Vamos usar o AWK". Agora eles tem dois problemas. - D. Tilbrook
É uma piada e uma verdadeira escavação, mas também é uma maneira de destacar o regex como uma solução ruim, vinculando-o a outras soluções ruins. É um ótimo ha ha, apenas um momento sério .
Para mim - lembre-se, esta citação é propositalmente aberta à interpretação - o significado é direto. O simples anúncio da idéia de usar uma expressão regular não resolveu o problema. Além disso, você aumentou a complexidade cognitiva do código adicionando um idioma adicional com regras que se destacam do idioma que você está usando.
Embora seja engraçado como uma piada, você precisa comparar a complexidade de uma solução que não seja regex com a complexidade da solução regex + a complexidade adicional de incluir regexes. Pode valer a pena resolver um problema com uma regex, apesar do custo adicional de adicionar regexes.
As Expressões regulares são agora um destinatário ou um outro conteúdo não formatado; na verdade, é provável que exista provavelmente uma leitura ou leitura desse item de texto; mas, infelizmente, existem uma
(Expressões regulares não são piores de ler ou manter do que qualquer outro conteúdo não formatado; na verdade, uma regex provavelmente é mais fácil de ler do que esta parte do texto aqui - mas infelizmente elas têm uma má reputação porque algumas implementações não permitem a formatação e as pessoas em geral não sei que você pode fazer isso.)
Aqui está um exemplo trivial:
^(?:[^,]*+,){21}[^,]*+$
O que não é realmente tão difícil de ler ou manter, mas é ainda mais fácil quando se parece com isso:
(?x) # enables comments, so this whole block can be used in a regex.
^ # start of string
(?: # start non-capturing group
[^,]*+ # as many non-commas as possible, but none required
, # a comma
) # end non-capturing group
{21} # 21 of previous entity (i.e. the group)
[^,]*+ # as many non-commas as possible, but none required
$ # end of string
Esse é um exemplo exagerado (comentar $
é semelhante a comentar i++
), mas claramente não deve haver problemas para ler, entender e manter isso.
Desde que você tenha certeza de quando expressões regulares são adequadas e quando é uma má ideia, não há nada errado com elas, e na maioria das vezes a cotação JWZ não se aplica realmente.
*+
? Como isso é diferente (funcionalmente) de apenas *
?
*+
neste caso; tudo está ancorado e pode ser correspondido em uma única passagem por um autômato que pode contar até 22. O modificador correto nesses conjuntos que não são vírgulas é simplesmente antigo *
. (Além do mais, também deve haver nenhuma diferença entre os algoritmos correspondentes gananciosos e não gananciosos aqui É um caso extremamente simples..)
Além da resposta de ChrisF - que expressões regulares "são difíceis de codificar, entender e manter", é pior: elas são poderosas o suficiente para induzir as pessoas a tentarem usá-las para analisar coisas que não podem, como HTML. Veja as inúmeras perguntas sobre SO em "como analiso HTML?" Por exemplo, a resposta mais épica de todos os SO!
Expressões regulares são muito poderosas, mas têm um pequeno e um grande problema; eles são difíceis de escrever e quase impossíveis de ler.
Na melhor das hipóteses, o uso da expressão regular resolve o problema; portanto, você só tem o problema de manutenção do código complicado. Se você não acertar a expressão regular, terá o problema original e o código ilegível que não funciona.
Às vezes, expressões regulares são chamadas de código somente gravação. Diante de uma expressão regular que precisa ser corrigida, geralmente é mais rápido começar do zero do que tentar entender a expressão.
O problema é que a regex é uma fera complicada e você só resolve o seu problema se usar a regex perfeitamente. Caso contrário, você terá 2 problemas: seu problema original e sua expressão regular.
Você afirma que ele pode fazer o trabalho de cem linhas de código, mas também pode argumentar que 100 linhas de código claro e conciso são melhores que uma linha de regex.
Se você precisar de alguma prova disso: Você pode conferir este SO Classic ou simplesmente vasculhar a tag SO Regex
O significado tem duas partes:
Como você solicitou em 2014, seria interessante focar nas ideologias das linguagens de programação do contexto de 1997 comparando com o contexto de hoje. Não vou entrar neste debate aqui, mas as opiniões sobre o Perl e o próprio Perl mudaram bastante.
No entanto, para permanecer em um contexto de 2013 ( sugiro que você lembre-se de todas as outras questões ), sugiro que me concentre na recriação de citações usando uma famosa história em quadrinhos do XKCD que é uma citação direta da de Jamie Zawinski :
Primeiro, tive problemas para entender essa história em quadrinhos porque era uma referência à citação de Zawinski, e uma citação de uma letra de uma música de Jay-z, e uma referência da program --help -z
bandeira 2 do GNU , então era muita cultura para eu entender.
Eu sabia que era divertido, estava sentindo, mas realmente não sabia o porquê. As pessoas costumam fazer piadas sobre Perl e expressões regulares, especialmente porque não é a linguagem de programação mais moderna, não sabem realmente por que ela deve ser divertida ... Talvez porque os vendedores de Perl façam coisas tolas .
Portanto, a citação inicial parece ser uma piada sarcástica baseada em problemas da vida real (dor?) Causados pela programação com ferramentas que doem. Assim como um martelo pode machucar um pedreiro, programar com ferramentas que não são as que um desenvolvedor escolheria se pudesse machucar (o cérebro, os sentimentos). Às vezes, ocorrem grandes debates sobre qual ferramenta é a melhor, mas é quase inútil porque é um problema do seu gosto ou do gosto da sua equipe de programação , razões culturais ou econômicas . Outra excelente história em quadrinhos do XKCD sobre isso:
Eu consigo entender as pessoas que sentem dor com as expressões regulares e acreditam que outra ferramenta é mais adequada para o que as expressões regulares foram projetadas. Como @ karl-bielefeldt responde à sua pergunta com grande expressividade, vem uma grande responsabilidade , e as expressões regulares estão especialmente preocupadas com isso. Se um desenvolvedor não se importar com o modo como ele lida com as expressões regulares, isso acabará prejudicando as pessoas que manterão o código posteriormente.
Terminarei com esta resposta sobre a reconstituição de citações por uma citação que mostra um exemplo típico das Perl Best Practices de Damian Conwy's (um livro de 2005).
Ele explica que escrever um padrão como este:
m{'[^\\']*(?:\\.[^\\']*)*'}
... não é mais aceitável do que escrever um programa como este :
sub'x{local$_=pop;sub'_{$_>=$_[0
]?$_[1]:$"}_(1,'*')._(5,'-')._(4
,'*').$/._(6,'|').($_>9?'X':$_>8
?'/':$")._(8,'|').$/._(2,'*')._(
7,'-')._(3,'*').$/}print$/x($=).
x(10)x(++$x/10).x($x%10)while<>;
Mas pode ser reescrito , ainda não é bonito, mas pelo menos agora é passível de sobrevivência.
# Match a single-quoted string efficiently...
m{ ' # an opening single quote
[^\\']* # any non-special chars (i.e., not backslash or single quote)
(?: # then all of...`
\\ . # any explicitly backslashed char
[^\\']* # followed by any non-special chars
)* # ...repeated zero or more times
' # a closing single quote
}x
Esse tipo de código de forma retangular é o segundo problema, não as expressões regulares que podem ser formatadas de maneira clara, sustentável e legível.
/* Multiply the first 10 values in an array by 2. */ for (int i = 0 /* the loop counter */; i < 10 /* continue while it is less than 10 */; ++i /* and increment it by 1 in each iteration */) { array[i] *= 2; /* double the i-th element in the array */ }
Se há algo que você deve aprender com a ciência da computação, é a hierarquia de Chomsky . Eu diria que todos os problemas com expressões regulares vêm de tentativas de analisar a gramática sem contexto. Quando você pode impor um limite (ou acha que pode impor um limite) aos níveis de aninhamento no CFG, você obtém essas expressões regulares longas e complexas.
Expressões regulares são mais adequadas para tokenização do que para análise em grande escala.
Mas, um conjunto surpreendentemente grande de coisas que os programadores precisam analisar são analisáveis por uma linguagem comum (ou, pior, quase analisável por uma linguagem comum e se você escrever um pouco mais de código ...).
Portanto, se alguém está habituado a "aha, eu preciso separar o texto, usarei uma expressão regular", é fácil seguir esse caminho, quando você precisa de algo mais próximo de um autômato push-down, um analisador CFG ou gramáticas ainda mais poderosas. Isso geralmente termina em lágrimas.
Então, acho que a citação não é tanto regexps violenta, eles têm seu uso (e bem usados, são muito úteis), mas a dependência excessiva de regexps (ou, especificamente, a escolha acrítica deles) .
jwz está simplesmente louco com essa citação. expressões regulares não são diferentes de qualquer recurso de idioma - fácil de estragar, difícil de usar com elegância, poderoso às vezes, inadequado às vezes, muitas vezes bem documentado, muitas vezes útil.
o mesmo pode ser dito para aritmética de ponto flutuante, fechamentos, orientação a objetos, E / S assíncrona ou qualquer outra coisa que você possa nomear. se você não sabe o que está fazendo, as linguagens de programação podem deixá-lo triste.
se você acha difícil ler expressões regulares, tente ler a implementação do analisador equivalente para consumir o padrão em questão. as regexes geralmente vencem porque são mais compactas do que os analisadores completos ... e na maioria dos idiomas também são mais rápidas.
não deixe de usar expressões regulares (ou qualquer outro recurso de idioma) porque um blogueiro autopromovido faz declarações não qualificadas. experimente você mesmo e veja o que funciona para você.
Minha resposta favorita e detalhada a isso é dada pelo famoso Rob Pike em uma postagem de blog reproduzida a partir de um comentário interno do código do Google: http://commandcenter.blogspot.ch/2011/08/regular-expressions-inclusing- and.html
O resumo é que eles não são ruins , mas são freqüentemente usados para tarefas para as quais não são necessariamente adequados, especialmente quando se trata de lexing e análise de algumas entradas.
Expressões regulares são difíceis de escrever, difíceis de escrever bem e podem ser caras em relação a outras tecnologias ... Os Lexers, por outro lado, são bastante fáceis de escrever corretamente (se não de forma compacta) e muito fáceis de testar. Considere encontrar identificadores alfanuméricos. Não é muito difícil escrever o regexp (algo como "[a-ZA-Z _] [a-ZA-Z_0-9] *"), mas realmente não é muito mais difícil escrever como um loop simples. O desempenho do loop, no entanto, será muito maior e envolverá muito menos código nos bastidores. Uma biblioteca de expressões regulares é uma grande coisa. Usar um para analisar identificadores é como usar uma Ferrari para ir à loja buscar leite.
Ele diz muito mais do que isso, argumentando que expressões regulares são úteis, por exemplo, correspondência descartável de padrões em editores de texto, mas raramente devem ser usadas em código compilado, e assim por diante. Vale a pena ler.
Isso está relacionado ao epigrama # 34 de Alan Perlis:
A cadeia de caracteres é uma estrutura de dados rígida e em todos os lugares em que é passada, há muita duplicação de processos. É um veículo perfeito para ocultar informações.
Portanto, se você escolher a cadeia de caracteres como sua estrutura de dados (e, naturalmente, o código baseado em regex como algoritmos para manipulá-la), você terá um problema, mesmo que funcione: mau design em torno de uma representação inadequada de dados, difícil de estender e ineficiente.
No entanto, muitas vezes não funciona: o problema original não é resolvido e, nesse caso, você tem dois problemas.
Regexes são amplamente usados para análise de texto rápida e suja. Eles são uma ótima ferramenta para expressar padrões um pouco mais complexos do que apenas uma correspondência simples de string.
No entanto, à medida que as expressões regulares ficam mais complexas, problemas de servidor surgem na cabeça.
Portanto, é muito fácil começar com um problema de processamento de texto, aplicar expressões regulares a ele e terminar com dois problemas, o problema original que você estava tentando resolver e lidar com as expressões regulares que estão tentando resolver (mas não resolvendo corretamente) o problema original.