Expressões Regulares: Conhecendo as ferramentas complementares

No artigo anterior, apresentamos uma introdução às Expressões Regulares. Vamos dar continuidade a esse tema, tratando de outras ferramentas (metacaracteres) e dando dicas um pouco mais avançadas. Primeiramente, vamos fazer uma revisão rápida das ferramentas já vistas:

.       Qualquer letra
[xyz]   Qualquer das letras dentro dos colchetes
[^xyz]  Qualquer letra fora as dentro dos colchetes
[t-z]   Qualquer das letras entre t e z
z*      Letra z zero ou mais vezes
z+      Letra z uma ou mais vezes

Bem, vamos começar a dar nomes aos bois e falar na língua que usuários de ERs entendem. Como já foi visto, o * e o + são quantificadores, pois indicam repetição da entidade anterior. Os [] são chamados de classe de caracteres, e o . é ponto mesmo.

Também foi visto que temos uma classe negada de caracteres, representada por [^ ] e ainda que podemos ter um intervalo dentro dessa classe, representado por um hífen - entre dois caracteres.

Uma dúvida que deve ter ficado: "e como colocar um ^, - ou ] literal dentro de uma classe de caracteres?". Bem, o ^ só é especial se for o primeiro dentro da classe, então basta colocá-lo em outra posição, como em [a^], que casa ou um a ou um ^. O hífen, basta colocá-lo como primeiro ou último da classe, e o ], ponha-o no início. Assim, [][^-] casa um ], ou [, ou ^ ou -. Olhe de novo a ER, com calma, respire, você vai compreender :)

Agora que relembramos as ferramentas já vistas, vamos aumentar nosso arsenal. A primeira novidade é a interrogação ?. Ela também é um quantificador, que casa a entidade anterior 0 ou 1 vez apenas, ou seja, ela pode ser encarada como opcional, pode existir ou não.

No exercício do artigo anterior, em que se propunha uma ER para casar a palavra "revista" no singular ou plural, simplesmente se faz revistas?. Sendo a letra s a entidade imediatamente anterior à ?, esta torna-se opcional, atingindo o objetivo.

Com os três quantificadores vistos até então, percebemos que podemos definir com ERs quantidades de 0, 1 ou muitos. Mas e no caso de procurarmos, por exemplo, um número de cinco dígitos? Claro, num primeiro momento, o mais óbvio seria [0-9][0-9][0-9][0-9][0-9]. Funciona, mas além de redundante, como faríamos se fossem quinze, vinte dígitos? Para se ter um controle mais refinado, temos o quantificador numérico: as chaves {}. Dentro delas se coloca a quantidade desejada de ocorrências da entidade anterior. No exemplo anterior do número de cinco dígitos, faríamos [0-9]{5}, ou seja, qualquer número entre 0 e 9, cinco vezes. Atenção aqui, não é o mesmo número repetido como 77777 e sim qualquer número do intervalo, cinco vezes, como 73956 por exemplo.

Mas o quantificador numérico é muito mais flexível que isso, pois além de números fixos de repetições, permite a definição de intervalos, como z{3,5}, que quer dizer: a letra z de três até cinco vezes, o que casaria zzz, zzzz e zzzzz. Além disso, podemos ter uma definição mais relaxada como {,5} e {3,}, que seriam "até 5" e "no mínimo 3", respectivamente.

Dê uma revisada em todos os quantificadores. Leitores mais atentos deverão perceber que os quantificadores *, + e ? são equivalentes a {0,}, {1,} e {0,1}. Pois é. Fazem a mesma coisa, mas os primeiros são mais curtos e fáceis de ler.

Até agora sempre que os quantificadores foram referenciados, se disse que eram relativos à "entidade" anterior. Essa entidade deve-se ao fato de que as ERs podem ser agregadas, ou seja, pode-se concatenar ERs, mesclando ferramentas e construindo-se ERs tão complexas quanto se necessite. Antes de começar a viajar no assunto de ERs agregadas, vamos ver mais uma ferramenta, o agrupamento, com os ().

Como numa expressão matemática, os parênteses definem um grupo, e seu conteúdo pode ser visto como um bloco à parte na expressão. Agora as ERs começam a ficar divertidas. Veja por exemplo (governa)?dor. A "entidade" que a interrogação deixou opcional neste caso foi todo o agrupamento dos parênteses, então essa ER casa governador e dor.

E ainda, como ferramenta complementar ao agrupamento, temos a alternância, representada pela barra vertical |. Seriam alternativas possíveis a uma posição, um "OU" lógico. Assim, vamos fazer uma ER que case algumas possibilidades de cargos públicos que poderíamos ocupar e não nos preocuparmos mais em aprender essas expressões complicadas...

Comecemos com (governa|sena|verea)dor. sem a ? no grupo, deixamos a dor atrelada aos três cargos públicos de uma só vez: governador, senador e vereador. Mas é claro, não podemos nos esquecer da ala feminina, para empregar a mulher, a irmã... Incluiremos um a opcional no final: (governa|sena|verea)dora?. Mas ainda faltam os primos, cunhados e afins, então cargos de vice pra eles: (vice-)?(governa|sena|verea)dora?. Uau! Nossa expressão agora reconhece oito cargos públicos:

  • governador
  • governadora
  • vice-governador
  • vice-governadora
  • senador
  • senadora
  • vice-senador
  • vice-senadora
  • vereador
  • vereadora
  • vice-vereador
  • vice-vereadora

A família toda está garantida :) Bem, deixando a politicagem de lado, creio que é perceptível o quão poderosa é a sintaxe das ERs, que com poucas ferramentas se consegue ser bem específico, conseguindo dizer muito com pouco.

Mas eu já falei que usando o agrupamento ganha-se um brinde? Não? Pois é, cada vez que se usa os parênteses, seu conteúdo (o que a ER casou) é automaticamente armazenado num registrador interno para poder ser usado mais para a frente na expressão. O nome é feio: referência retroativa, mas essa característica é ótima para procurar coisas repetidas, por exemplo, ao procurar a palavra quero-quero, a ER seria: (quero)-\1. A forma de se referir ao conteúdo do registrador é um número de 1 a 9 com uma barra invertida na frente. Chama-se isso de "número escapado".

Um uso muito comum dessa referência é a procura de palavras repetidas num texto como como estas. Basta a ER ([A-Za-z]+) \1 para encontrá-las, ou seja, qualquer cadeia de letras maiúsculas ou minúsculas seguida de um espaço em branco e seguida da mesma cadeia novamente.

Pode-se fazer uso de até nove registradores sempre contando da esquerda para a direita. Então algo como:

Já (vi) o (quero)-\2 (hoje), mas \3 não \1m aqui para vê-lo

é traduzido para:

Já vi o quero-quero hoje, mas hoje não vim aqui para vê-lo

Note que os () não alteram o sentido da ER, apenas servem como marcadores. Com isso já demos um grande salto no aprendizado das ERs. Se precisar, dê uma relida nos conceitos para entendê-los bem, pois a base é isso, o que vem pela frente agora é aplicação disso no mundo real, exemplos práticos, que podem ser executados na linha de comando e detalhes que não são documentados, que só se aprende na prática.

Mencionei que as ERs também podem ser aninhadas? Não? Bom, então essa viagem fica para o próximo artigo...

E como exemplos são melhores que páginas de teoria:

ER       Casa as cadeias
------   -----------------------
[ajz]    a j z
[t-z]    t u v w x y z
z*       nada z zz zzz zzzz ...
z+       z zz zzz zzzz ...
z{2}     zz
z{2,4}   zz zzz zzzz
z{,3}    nada z zz zzz
z{3,}    zzz zzzz zzzzz ...
(a|j)z   az jz
(aj)*    nada aj ajaj ajajaj ...
[aj]*    nada a j aa ajjaaj ...
(a|j)*   nada a j aa ajjaaj ...
(aj)\1   ajaj
.*       Para pensar com calma

Observação: este último é um ponto chave das ERs.

« Leia a primeira parte deste artigo

Artigo originalmente publicado na Revista do Linux edição 7, de julho de 2000.

— EOF —

Aprenda mais sobre Expressões Regulares