Usando asserções lookahead em expressões regulares

5

Eu uso expressões regulares diariamente, pois meu trabalho diário é de 90% em Perl (base de código legado, mas isso é um problema diferente). Apesar disso, ainda acho que lookahead e lookbehind são terrivelmente confusos e muitas vezes ilegíveis. No momento, se eu fosse fazer uma revisão de código com lookahead ou lookbehind, eu a enviaria imediatamente para ver se o problema pode ser resolvido usando várias expressões regulares ou uma abordagem diferente. A seguir, os principais motivos pelos quais eu não gosto deles:

  • Eles podem ser terrivelmente ilegíveis. As afirmações antecipadas, por exemplo, começam no início da cadeia, independentemente de onde elas são colocadas. Isso, entre outras coisas , pode causar alguns "interesses" "e comportamentos não óbvios.
  • Costumava acontecer que muitas linguagens não suportavam lookahead / lookbehind (ou as suportavam como "recursos experimentais"). Este não é o caso tanto, mas ainda há sempre a questão de quão bem ele é suportado.
  • Francamente, eles se sentem como um hack sujo. Os regexps geralmente já são, mas também podem ser bastante elegantes e ganharam ampla aceitação.
  • Eu passei sem nenhuma necessidade deles ... às vezes eu acho que eles são estranhos.

Agora, eu admito abertamente que especialmente as duas últimas razões não são boas, mas eu senti que deveria enumerar o que passa pela minha mente quando vejo uma. Estou mais do que disposto a mudar de idéia sobre eles, mas sinto que eles violam alguns dos meus principais princípios de programação, incluindo:

  • O código deve ser o mais legível possível sem sacrificar a funcionalidade - isso pode incluir fazer algo de maneira menos eficiente, mas mais clara, desde que a diferença seja insignificante ou insignificante para o aplicativo como um todo.
  • O código deve ser passível de manutenção - se outro programador aparecer para consertar meu código, um comportamento não óbvio pode ocultar bugs ou fazer com que o código funcional pareça com erros (veja legibilidade)
  • "A ferramenta certa para o trabalho certo" - Tenho certeza de que você pode criar exemplos planejados que possam usar lookahead, mas nunca encontrei algo que realmente precise deles no meu trabalho de desenvolvimento do mundo real. Existe alguma coisa que eles são realmente a melhor ferramenta para, ao contrário, digamos, múltiplos regexps (ou, alternativamente, eles são a melhor ferramenta para a maioria dos casos que são usados hoje)?

Minha pergunta é: É uma boa prática usar lookahead / lookbehind em expressões regulares ou eles são simplesmente um hack que encontrou seu caminho no código de produção moderno?

Eu ficaria perfeitamente feliz em estar convencido de que estou errado sobre isso, e exemplos simples são úteis para exemplos ou ilustrações, mas por si só, não serão suficientes para me convencer.

    
por Greg Jackson 24.06.2011 / 11:36
fonte

2 respostas

6

I still find lookahead and lookbehind to be terribly confusing and often unreadable.

Você está ciente de que expressões regulares podem ser explodidas e comentadas, certo?

$foo =~ m/^
  (?=.*a)           # must contain an a somewhere
  (?=.*c)           # must contain a c somewhere
  (?=.*1)           # must contain a 1 somewhere
  (?=.*2)           # must contain a 2 somewhere
  \S+               # all non-space characters
$/x

Is it good practice to use lookahead/lookbehind in regular expressions, or are they simply a hack that have found their way into modern production code?

Eles são absolutamente indispensáveis para evitar retrocessos catastróficos e problemas de segurança relacionados ao assunto . Idealmente, use também grupos atômicos .

Compare como a expressão acima voltará, em comparação com o equivalente ingênuo:

$foo =~ m/^
  \S*a\S*c\S*1\S*2\S*      # a, then c, then 1, then 2
 |
  \S*a\S*c\S*2\S*1\S*      # a, c, 2, 1
 |
  \S*a\S*1\S*c\S*2\S*      # a, 1, c, 2
 |
  \S*a\S*1\S*2\S*c\S*      # a, 1, 2, c
 |
  # ... etc
$/x

Especialmente com uma entrada longa e uma sequência aleatória de a, ce 2 (no 1).

    
por 24.06.2011 / 11:58
fonte
1

Para ter uma visão muito geral, você terá que pesar os trade-offs uns contra os outros. Por um lado, você tem um recurso avançado que é suportado apenas por algumas implementações, que serão difíceis de ler, a menos que você seja muito hábil com isso. Por outro lado, você tem um pedaço de código (muito mais provável) usando construções mais simples. Qual deles é o melhor depende da acessibilidade (diretamente relacionada ao programador original e sua própria proficiência ) e preocupações mais abstratas como precisão e velocidade . Como regra geral, minha opinião (depois de usar regexes por cerca de uma década):

  • A menos que o código seja descartado (e todos nós sabemos como isso termina ), use regexes com moderação. Eles são um pouco como montar um modelo 8-dimensional do problema, e desembaraçá-los é, portanto, difícil.
  • Não equacione um regex curto com um tempo de processamento curto. Uma construção de cinco linhas substr / if-else poderia muito bem ser mais rápida, então tente antes de se comprometer com uma abordagem.
  • Muitas vezes fica incrivelmente difícil lidar com casos de canto (veja todas as pessoas perguntando sobre regexes para analisar HTML). Divida e conquiste em vez de comer toda a cadeia de estilo regex.
por 24.06.2011 / 13:47
fonte