Aprendendo expressões regulares [fechado]

166

Eu realmente não entendo expressões regulares. Você pode me explicar de uma maneira fácil de seguir? Se houver alguma ferramenta ou livro on-line, você também pode vincular a eles?

Teifion
fonte

Respostas:

789

A parte mais importante são os conceitos. Depois de entender como os blocos de construção funcionam, as diferenças de sintaxe chegam a pouco mais do que dialetos suaves. Uma camada na parte superior da sintaxe do mecanismo de expressões regulares é a sintaxe da linguagem de programação que você está usando. Idiomas como o Perl removem a maior parte dessa complicação, mas você deve ter em mente outras considerações se estiver usando expressões regulares em um programa em C.

Se você pensa em expressões regulares como blocos de construção que podem ser combinados e combinados como quiser, ajuda a aprender a escrever e depurar seus próprios padrões, mas também a entender os padrões escritos por outras pessoas.

Comece simples

Conceitualmente, as expressões regulares mais simples são caracteres literais. O padrão Ncorresponde ao caractere 'N'.

Expressões regulares próximas umas das outras correspondem às seqüências. Por exemplo, o padrão Nickcorresponde à sequência 'N' seguida de 'i' seguida de 'c' seguida de 'k'.

Se você já usou grepno Unix - mesmo que apenas procure por strings comuns - você já está usando expressões regulares! (O rein greprefere-se a expressões regulares.)

Encomendar a partir do menu

Adicionando um pouco de complexidade, você pode combinar 'Nick' ou 'nick' com o padrão [Nn]ick. A parte entre colchetes é uma classe de caracteres , o que significa que corresponde exatamente a um dos caracteres incluídos. Você também pode usar intervalos em classes de caracteres, portanto, [a-c]corresponde a 'a' ou 'b' ou 'c'.

O padrão .é especial: em vez de corresponder apenas a um ponto literal, ele corresponde a qualquer caractere . É o mesmo conceito que a classe de personagens realmente grandes [-.?+%$A-Za-z0-9...].

Pense nas classes de personagens como menus: escolha apenas uma.

Atalhos úteis

O uso .pode economizar bastante digitação e existem outros atalhos para padrões comuns. Digamos que você queira combinar um dígito: é uma maneira de escrever [0-9]. Os dígitos são um destino de correspondência frequente; portanto, você pode usar o atalho \d. Outros são \s(espaço em branco) e \w(caracteres da palavra: alfanuméricos ou sublinhado).

As variantes em maiúsculas são seus complementos; portanto, \Scorresponde a qualquer caractere que não seja um espaço em branco, por exemplo.

Uma vez não é suficiente

A partir daí, você pode repetir partes do seu padrão com quantificadores . Por exemplo, o padrão ab?ccorresponde a 'abc' ou 'ac' porque o ?quantificador torna opcional o subpadrão que ele modifica. Outros quantificadores são

  • * (zero ou mais vezes)
  • + (uma ou mais vezes)
  • {n}(exatamente n vezes)
  • {n,}(pelo menos n vezes)
  • {n,m}(pelo menos n vezes, mas não mais que m vezes)

Juntando alguns desses blocos, o padrão [Nn]*ickcorresponde a todos

  • ick
  • usuario
  • usuario
  • Nnick
  • nNick
  • nnick
  • (e assim por diante)

A primeira partida demonstra uma lição importante: *sempre consegue! Qualquer padrão pode corresponder a zero vezes.

Alguns outros exemplos úteis:

  • [0-9]+(e seu equivalente \d+) corresponde a qualquer número inteiro não negativo
  • \d{4}-\d{2}-\d{2} corresponde a datas formatadas como 01-01-2019

Agrupamento

Um quantificador modifica o padrão para sua esquerda imediata. Você pode 0abc+0combinar '0abc0', '0abcabc0' e assim por diante, mas o padrão imediatamente à esquerda do quantificador positivo é c. Isso significa que 0abc+0combina '0abc0', '0abcc0', '0abccc0' e assim por diante.

Para combinar uma ou mais seqüências de 'abc' com zeros nas extremidades, use 0(abc)+0. Os parênteses indicam um subpadrão que pode ser quantificado como uma unidade. Também é comum que os mecanismos de expressão regular salvem ou "capturem" a parte do texto de entrada que corresponde a um grupo entre parênteses. Extrair bits dessa maneira é muito mais flexível e menos propenso a erros do que contar índices e substr.

Alternação

Anteriormente, vimos uma maneira de combinar 'Nick' ou 'nick'. Outra é com alternância como em Nick|nick. Lembre-se de que a alternância inclui tudo à sua esquerda e tudo à sua direita. Use agrupamento parênteses para limitar o escopo de |, por exemplo , (Nick|nick).

Para outro exemplo, você poderia escrever equivalentemente [a-c]como a|b|c, mas isso provavelmente será abaixo do ideal, porque muitas implementações assumem que as alternativas terão comprimentos maiores que 1.

Escapando

Embora alguns personagens se correspondam, outros têm significados especiais. O padrão \d+não corresponde à barra invertida seguida por D minúsculo seguido de um sinal de mais: para conseguir isso, usaríamos \\d\+. Uma barra invertida remove o significado especial do seguinte caractere.

Ganância

Os quantificadores de expressão regular são gananciosos. Isso significa que eles correspondem ao máximo de texto possível, permitindo que o padrão inteiro seja correspondido com êxito.

Por exemplo, digamos que a entrada seja

"Olá", disse ela, "como vai você?"

Você pode esperar ".+"corresponder apenas a "Olá" e ficará surpreso ao ver que ele correspondeu de "Olá" até "você?".

Para mudar de ganancioso para o que você pode considerar cauteloso, adicione um extra ?ao quantificador. Agora você entende como \((.+?)\), o exemplo da sua pergunta funciona. Corresponde à sequência de um parêntese esquerdo literal, seguido por um ou mais caracteres e terminado por um parêntese direito.

Se sua entrada for '(123) (456)', a primeira captura será '123'. Quantificadores não gananciosos desejam permitir que o restante do padrão comece a corresponder o mais rápido possível.

(Quanto à sua confusão, não conheço nenhum dialeto de expressão regular ((.+?))que faça a mesma coisa. Suspeito que algo tenha se perdido na transmissão em algum ponto do caminho.)

Âncoras

Use o padrão especial ^para corresponder apenas no início de sua entrada e $corresponder apenas no final. Fazer "suportes para livros" com seus padrões, onde você diz: "Eu sei o que está na frente e nas costas, mas me dê tudo entre" é uma técnica útil.

Digamos que você queira corresponder aos comentários do formulário

-- This is a comment --

você escreveria ^--\s+(.+)\s+--$.

Construa o seu próprio

Expressões regulares são recursivas, portanto, agora que você entende essas regras básicas, pode combiná-las como quiser.

Ferramentas para escrever e depurar expressões regulares:

Livros

Recursos gratuitos

Nota de rodapé

†: A afirmação acima que .corresponde a qualquer caractere é uma simplificação para fins pedagógicos que não é estritamente verdadeira. O ponto corresponde a qualquer caractere, exceto a nova linha, "\n"mas, na prática, você raramente espera um padrão que .+ultrapasse o limite da nova linha. As expressões regulares Perl têm um /sswitch e Java Pattern.DOTALL, por exemplo, para fazer a .correspondência com qualquer caractere. Para idiomas que não possuem esse recurso, você pode usar algo como [\s\S]"qualquer espaço em branco ou qualquer espaço em branco", ou seja, qualquer coisa.

Greg Bacon
fonte
14
Você também pode usar método de tentativa e erro e de seguir testador de regex online e depurador pode ser uma grande ajuda: regex101.com
Juraj.Lorinc
2
Vale ressaltar que, apesar de ser um padrão semelhante, a{,m}não é uma coisa, pelo menos em Javascript, Perl e Python.
Fund Monica's Lawsuit
2
Vale a pena mencionar que existem diferentes tipos de mecanismos de expressão regular, todos com diferentes conjuntos de recursos e regras sintáticas.
hek2mgl
1
O hackr.io/tutorials/learn-regular-expressions-regex é um ótimo lugar para encontrar os melhores tutoriais online sobre regex. Todos os tutoriais aqui são enviados e recomendados (votados como SO) pela comunidade de programação.
Saurabh Hooda
2
Agradecemos seus esforços para trazer tudo aqui em poucas palavras.
Saurabh Tiwari