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?
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.
Conceitualmente, as expressões regulares mais simples são caracteres literais. O padrão N
corresponde ao caractere 'N'.
Expressões regulares próximas umas das outras correspondem às seqüências. Por exemplo, o padrão Nick
corresponde à sequência 'N' seguida de 'i' seguida de 'c' seguida de 'k'.
Se você já usou grep
no Unix - mesmo que apenas procure por strings comuns - você já está usando expressões regulares! (O re
in grep
refere-se a expressões regulares.)
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.
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, \S
corresponde a qualquer caractere que não seja um espaço em branco, por exemplo.
A partir daí, você pode repetir partes do seu padrão com quantificadores . Por exemplo, o padrão ab?c
corresponde 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]*ick
corresponde a todos
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-2019Um quantificador modifica o padrão para sua esquerda imediata. Você pode 0abc+0
combinar '0abc0', '0abcabc0' e assim por diante, mas o padrão imediatamente à esquerda do quantificador positivo é c
. Isso significa que 0abc+0
combina '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
.
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.
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.
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.)
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+--$
.
Expressões regulares são recursivas, portanto, agora que você entende essas regras básicas, pode combiná-las como quiser.
†: 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 /s
switch 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.
a{,m}
não é uma coisa, pelo menos em Javascript, Perl e Python.