Expressões regulares, o básico – parte 1

regex1_abertura

Expressão regular — ou simplesmente REGEX para encurtar — é uma sequência de caracteres que define um padrão de busca, é geralmente utilizada dentro de algoritmos de pesquisa de texto para busca e/ou substituição de sequências/padrões de caracteres dentro de strings e Por sua praticidade, está implementada dentro de linguagens de programação, ferramentas e até mesmo alguns aplicativos.

Claro que isto aqui não tem o objetivo de ser um tratado sobre o assunto, servindo mais como uma introdução básica para que a visão de algo como um ^[A-Za-z]+ [0-9].*[A-Z][a-z]+$ deixe de causar traumático.

Nesta primeira parte dois conceitos importantes em REGEX, a quantificação (número de vezes que repete, ou não) e o grupo (lista de possíveis ocorrências). E para os exemplos resolvi usar um trauma pessoal, a grafia do meu nome, ou seja, aquilo que me faz recitar o mantra “com «i», dois «n» e «i» no final” sempre que preciso explicar a alguém como escrever meu nome. 🙂

Antes de começar

Então, a primeira coisa a fazer é criar o combinador responsável por produzir as 48 grafias possíveis e foneticamente equivalentes do meu nome na língua portuguesa.


#!/bin/bash
let CASE=0
for A in 'Ge' 'Gi' 'Gy' 'J' ; do
for B in 'v' 'w' ; do
for C in 'n' 'nn'; do
for D in 'e' 'i' 'y' ; do
let CASE++
printf "Caso %02d – %so%sa%s%s%s\n" $CASE $A $B $C $D
done
done
done
done

view raw

names.sh

hosted with ❤ by GitHub

Execute o programa, escolha um dos casos e o pronuncie um dos nomes impressos e perceba como soarão parecidos.

Mas, por enquanto, o que importa é verificar apenas uma das grafias, a correta:

$ ./names.sh | grep "Giovanni"
Caso 17 - Giovanni

Neste caso apenas uma ocorrência foi encontrada, o que está certo pois é justamente o que foi pedido para ser pesquisado numa comparação de strings feita caractere por caractere.

E agora começamos com o “jogo de achar Giovanni”.

Quantificação de caracteres

Como na língua portuguesa a repetição da letra «n» não tem função fonética e o resultado final é acabarem sendo tratadas como se uma única letra fossem uma das letras «n» pode ser omitida em alguns casos. Então como achar “Giovanni” e “Giovani” sem recorrer a algo do tipo?

if [[ ${NOME} == "Giovanni" || ${NOME} == "Giovani" ]]; then
    ...
fi

Uma das formas de tratar a repetição de um caractere (ou a sequência destes) em REGEX é indicando entre chaves — { e } — a quantidade de vezes em que se repetirá.

Especificamente neste caso a letra «n» deverá aparecer no mínimo uma vez e no máximo duas vezes (estou desconsiderando a hipótese da letra «n» se repetir três ou mais vezes).

$ ./names.sh | egrep "Giovan{1,2}i"
Caso 14 - Giovani
Caso 17 - Giovanni

Ah sim, duas coisas, as cores são apenas para ajudar a visualizar a parte da string afetada pelo REGEX, e o uso do egrep equivale a utilizar grep -E.

A sintaxe dos valores dentro das chaves pode ser a seguinte:

  • n{2} — Duas ocorrências da letra «n»;
  • n{,2} — Até duas ocorrências da letra «n» ou nenhuma e
  • n{2,} — No mínimo duas repetições da letra «n», sem uma quantidade máxima definida.

Há outra forma de tratar quantidades, acrescentando o sinal de soma — + — após o caractere para indicar uma ou mais ocorrências do mesmo, funcionando como se fosse o “n{1,}” e, portanto, não servindo para este caso.

Um ou outro caractere

Outro erro comum é a troca da letra «i» pela letra «e» no começo, no final ou em ambos. Aqui é preciso verificar esta permuta ou mais precisamente a ocorrência destas duas alternativas com a criação de grupo contendo os caracteres que poderão aparecer naquela sequência de caracteres.

Para criar um grupo em REGEX basta listar as alternativas colocando-as entre parênteses — ( e ) — e utilizando a barra vertical — | — para separá-las.

Testando primeiro com um grupo no começo do nome:

$ ./names.sh | egrep "G(e|i)ovan{1,2}i"
Caso 02 - Geovani
Caso 05 - Geovanni
Caso 14 - Giovani
Caso 17 - Giovanni

Depois um grupo no final do nome:

$ ./names.sh | egrep "Giovan{1,2}(e|i)"
Caso 13 - Giovane
Caso 14 - Giovani
Caso 16 - Giovanne
Caso 17 - Giovanni

E finalmente com os dois grupos:

$ ./names.sh | egrep "G(e|i)ovan{1,2}(e|i)"
Caso 01 - Geovane
Caso 02 - Geovani
Caso 04 - Geovanne
Caso 05 - Geovanni
Caso 13 - Giovane
Caso 14 - Giovani
Caso 16 - Giovanne
Caso 17 - Giovanni

Lembrando que é possível usar mais de um caractere dentro do grupo e até grupos dentro de grupos.

Grupo dentro de grupo

E se ao invés da letra «G» for utilizada a letra «J»? Claro que aqui vou considerar a destruição do ditongo com as letras «e» e «i» deixando de existir e toda a sílaba virando «Jo».

$ ./names.sh | egrep "(J|G(e|i))ovan{1,2}(e|i)"
Caso 01 - Geovane
Caso 02 - Geovani
Caso 04 - Geovanne
Caso 05 - Geovanni
Caso 13 - Giovane
Caso 14 - Giovani
Caso 16 - Giovanne
Caso 17 - Giovanni
Caso 37 - Jovane
Caso 38 - Jovani
Caso 40 - Jovanne
Caso 41 - Jovanni

E agora apareceu o caso 38,  justamente a grafia da foto! 🙂

Finalizando esta parte

Adicionando agora um pouco mais de entropia com as letras «w» e «y»! A primeira formando um novo grupo com a letra «v» e a outra sendo adicionada aos grupos “(e|i)”.

$ ./names.sh | egrep "(J|G(e|i|y))o(v|w)an{1,2}(e|i|y)"
Caso 01 - Geovane
Caso 02 - Geovani
...
Caso 47 - Jowanni
Caso 48 - Jowanny

Liberando assim todas as 48 grafias criadas pelo programa e terminando esta primeira parte. Para a próxima parte será a vez de trabalhar com um pouco de incerteza com a ajuda dos curingas.

Até!

4 comentários sobre “Expressões regulares, o básico – parte 1

  1. Pingback: Expressões regulares, o básico – parte 2 | giovannireisnunes

  2. Pingback: Expressões regulares, o básico – parte 3 | giovannireisnunes

  3. Que maravilha essa série de artigos Giovanni! Explicou muito bem e escolheu exemplos que ilustram bem os conceitos. A formatação com cores também ajuda bastante a enxergar os casamentos. Nota 10!

    Curtir

Os comentários estão desativados.