DEV Community

Cover image for Vamos falar de RegEx?
Toshi Ossada for flutterbrasil

Posted on

Vamos falar de RegEx?

Fala Devs, blz?

Um dos meus pontos fracos durante minha vida de programador sempre foi Expressões Regulares pois sempre achei que fosse um bicho de sete cabeças cheio de regras e complicações. Recentemente resolvi estudar um pouco mais a fundo sobre Expressões Regulares e percebi que são bem mais simples do que imaginava e neste post irei mostrar como é simples e prático montarmos nossas próprias expressões regulares.

Se você não é um desenvolvedor Flutter/Dart pode continuar neste artigo pois falaremos sobre os conceitos das expressões regulares que será muito útil para você independente da linguagem de programação que utiliza. E posteriormente haverá a segunda parte que daí sim colocaremos o dart e o flutter em pratica.

Mas o que são Expressões Regulares?

Popularmente conhecida como RegEx possui uma definição simplificada:

Uma expressão regular é um método formal de se especificar um padrão de texto.

Ou seja, através de um padrão de textos conseguimos procurar textos, Substituir textos, validar formatos de textos e filtrar de informações.

Um exemplo clássico é validar se um texto é um e-mail.

contato@toshiossada.dev

Podemos notar que todo e-mail possui um padrão, o primeiro deles é o usuário que é composto por letras, números, ponto ou hífen — contato@toshiossada.dev.

Depois podemos perceber que ele é composto por um arroba (@) contato*@toshiossada.dev, logo em seguida temos o domínio que será composto por letras ou números contato@toshiossada*.dev

A categoria do domínio que será composto por ponto mais uma palavra de 2 ou 3 letras (Ex. .com, .dev, .co) — contato@toshiossada*.dev*

E por último temos a palavra opcional que é o código do país que também única com um ponto e pode ter de 2 a 3 letras (Ex. .br, .jp, .de). — contato@toshiossada.com.br

Com isso podemos validar se o texto é um e-mail com a seguinte Expressão Regular, mas calma, não se assuste, parece complicado mas irei explicar cada um desses símbolos mais tarde

^([.-_a-zA-Z0–9])+@([a-zA-Z0–9])+((.+[a-zA-Z0–9]{2,3}){1,2})$

Se jogarmos essa RegEx no site http://www.regexplained.co.uk/ nós teremos a explicação dessa expressão:

Também conseguimos fazer testes com o site https://www.regexpal.com/

*Metacaracteres . ? ^ $ | [] {} () *

Agora que entendemos o que é uma expressão regular e para que ela serve vamos falar de metacaracteres, que são aqueles caracteres esquisitos que compõem as expressões regulares, os metacaracteres são *. ? ^ $ | [] {} () * e a combinações deles que nos possibilita criar infinidades de expressões regulares.

Para melhor compreensão vamos dividir esses metacaracteres em quatro grupos: os representantes, os quantificadores, as âncoras e os outros.

Representantes

Primeiramente temos o grupo dos representantes que possuem três metacaracteres

O primeiro deles é o .(PONTO) a função dele nas expressões regulares é representar um caractere qualquer.

Vamos supor que queiramos identificar a palavra não na frase

nao

não

sim

Neste caso podemos perceber que há a variação de nao(sem acento) e não(com acento) e que existe um padrão entre as palavras, ambas iniciam com N e finaliza com a letra O, então podemos dizer que a segunda letra pode ser uma letra qualquer e é neste caso que entra o ponto, podemos criar a expressão regular da seguinte maneira.

n.o

Desta maneira ele identificara ambas as palavras

A lista […] representa uma lista de caracteres permitidos.

No exemplo anterior temos um problema, pois utilizando o ponto, qualquer palavra de 3 letras iniciada em N e finalizada em O irá ser considerada, por exemplo:

Daí que entra a lista, podemos delimitar os caracteres que serão considerados em nossa expressão, TODO CARACTERE NA LISTA É UTILIZADO EM SUA FORMA LITERAL. então nossa RegEx ficará da seguinte forma.

n[aAãÃ]o

lista negada[^…] tem a função contrária da lista, ela representa a lista de caracteres que não serão permitidas.

Um exemplo seria caso eu queira identificar as palavras que não sejam o NÃO

n[^aAãÃ]o

Uma funcionalidade interessante é de adicionar range (invervalos) dentro dos nossos conjuntos. Podemos determinar um conjunto de match em letras que vão de A à Z ou pegue qualquer digito (0 à 9).

Eu também posso utilizar todos os ranges juntos

[A-Za-z0–9]

Podemos também dar match em letras com acentos (é-à) ou (ç) usando:

[À-é]

Quantificadores

Uma maneira de deixar suas regras ainda mais simples é com o uso dos quantificadores. Com eles podemos dizer quantas vezes uma mesma regra pode aparecer em sequência.

Seu uso é simples, basta adicionar o quantificador após um caractere, metacaracteres, conjunto ou mesmo um grupo

O primeiro metacaracteres da lista é o opcional que é representado por um ponto de interrogação (?) a função dele é dizer para minha expressão regular que um carácter pode ou não estar contido (zero ou uma ocorrência).

Vamos validar se um CPF foi digitado em sua forma correta, o padrão que temos para CPF é 3 números (ponto) 3 números (ponto) 3 números (traço) 2 números. o PONTO e o TRAÇO são opcionais, pois o usuário pode informar o CPF 825.531.760–07 ou 82553176007 ambos deveriam estar válidos, então basta eu adicionar o ponto de interrogação à frente do caractere.

[0–9][0–9][0–9].?[0–9][0–9][0–9].?[0–9][0–9][0–9]-?[0–9][0–9]

Note que nesta expressão eu quero usar o carácter ponto em sua forma literal e não na função de qualquer caractere então utilizamos o escape ** para isso. O resultado será:

Em seguida temos o asterisco (*****) a função dele é semelhante ao ponto de interrogação, mas ao invés de tornar um caractere opcional ele torna uma expressão opcional (zero ou mais ocorrências), como um grupo. Ex.

a+[ar]*

Já o mais(+) tem a função de tornar a expressão ou caractere obrigatória, ou seja deve ocorrer pelo menos UMA vez. Ex.

[0–9]+.?[0–9]+.?[0–9]+-?[0–9]+

Por fim as chaves {n, m} referem-se ao tamanho que um grupo pode possuir, lembrando que o pode ser um único valor passando apenas o parâmetro {n} (Ex. {2}) ou pode ser um range passando o valor {n, m} (Ex. {2, 5}). No exemplo anterior podemos delimitar a quantidade de números entre os pontos, que são 3, 3, 3 e 2. Ficaria

[0–9]{3}.?[0–9]{3}.?[0–9]{3}-?[0–9]{2}

Também temos casos que o CPF pode ter dígito X, nesse caso teremos apenas 1 único caractere após o traço, podemos então colocar um range de 1 a 2 caracteres após o traço.

[0–9]{3}.?[0–9]{3}.?[0–9]{3}-?[0–9A-z]{1,2}

Âncoras

Às vezes necessitamos localizar uma posição em nossa frase para delimitar ações de nossas expressões regulares. Para isto existem três metacaracteres que podem nos auxiliar e contemplam o grupo das âncoras.

Primeiramente temos o circunflexo ^, que representa o início da linha

Já o cifrão $ indica o final da linha

Imagine que queira identificar somente as ocorrências que tenham somente uma tag HTML, nossa RegEx ficaria da seguinte forma

^<[a-zA-Z]+>$

Note que as ocorrências que tem uma tag HTML com um texto a mais não são identificados, isso porque delimitamos que o começo da linha deve conter < e o final >

E quando queremos tratar uma palavra que em suas extremidades não possua outra letra ou palavra, usamos a borda \b. Ex.

\bdia\b

Outros

Por fim temos metacaracteres que não se encaixam em nenhum grupo mas que são tão importantes como os outros metacaracteres.

O escape *tem como função utilizar algum caractere em sua forma literária, por exemplo *+ ou .

Já vimos o exemplo acima quando fizemos o exemplo do CPF

[0–9]{3}.?[0–9]{3}.?[0–9]{3}-?[0–9A-z]{1,2}

O pipe | tem a função de OU assim como nas estruturas de condições.

Se quisermos recuperar as saudações em uma frase (bom-dia, boa-tarde ou boa-noite) podemos utilizar da seguinte forma:

bo(m|a)-(dia|tarde|noite)

Grupos

Temos também os grupos (…) que nos possibilita criar varias expressões regulares e depois agrupa-las

Com isso temos a possibilidade de criação de referências utilizando os retrovisores para o reuso da mesma regra em outro local dentro de uma mesma RegEx e ainda cria a possibilidade de validações dentro da regex. Seu uso é muito diverso, dando muito poder ao programador na hora de escrever suas regras.

Suponha que tenho um RegEx para identificar datas

[0–9]{2}(\/|-)[0–9]{2}(\/|-)[0–9]{2,4}

Poderíamos resumir em

[0–9]{2}(\/|-)[0–9]{2}\1[0–9]{2,4}

Vale lembrar que os retrovisores irão dar match com exatamente o mesmo valor, você pode ter imaginado “não poderia ter utilizado os retrovisores para os meses?”

([0–9]{2})+(\/|-)+\1+\2+([0–9]{4})+

Não meu jovem padawan, pois os retrovisores verificam se é exatamente o mesmo Match e só funcionarão se o dia e o mês fosse idênticos.

Por exemplo se tivesse a frase “Hoje é dia 01/01/2020” a data 01/01/2020 seria reconhecida

Um Pouco mais dos Grupos

Até o momento vimos que é possível recuperar o resultado da expressão regular completa, mas com grupos é possível obter somente o resultado de um determinado grupo.

Vamos utilizar a seguinte RegEx

<+([a-zA-Z0–9]+)>+([a-zA-Z0–9/ ])+<([/])+([a-zA-Z0–9]+)>

o RegEx além de capturar a combinação completa também irá subdividir o resultado em grupos

Também podemos ignorar algum grupo para não ser capturado e não retornar o valor nos grupos, no exemplo acima o Grupo 3 me trás somente uma barra e eu não gostaria que ele viesse como um grupo separado, basta ?: ao início do grupo

<+([a-zA-Z0–9]+)>+([a-zA-Z0–9/ ])+<(?:[/])+\1>

Como resultado teremos

POSIX

Até o momento já vimos todos os conceitos básicos de RegEx e até este ponto você já conseguiria escrever qualquer tipo de expressão regular. Entretanto os RegEx possuem facilitadores/atalhos que representam um grupo de valores e que irão lhe economizar algum tempo e que são muito utilizados, vamos falar das classes POSIX.

A lista de POSIX são essas

Calma! pode parecer um pouco complicado decorar essas classes, mas para facilitar ainda mais nossa vida existem alguns atalhos para essas classes POSIX, são eles

Então se eu quiser colocar no meu regex uma lista de números ao invés de digitar [0–9] posso utilizar o \d e se quiser ignorar todos os números ao invés de utilizar o [^0-9] utilizarei o \D.

Note que existe um padrão, quando o atalho for na letra minúscula significa que a lista de POSIX está inclusa e se estiver em letra maiúscula é a negação da lista POSIX.

No exemplo do CPF ao invés de utilizarmos

[0–9]{3}.?[0–9]{3}.?[0–9]{3}-?[0–9xX]{1,2}

Podemos simplificar e obteremos o mesmo resultado

\d{3}.?\d{3}.?\d{3}-?[\dxX]{1,2}

Outro exemplo que podemos fazer é a validação de email

Ao invés de

^([.-_a-zA-Z0–9])+@([a-zA-Z0–9])+((.+[a-zA-Z]{2,3}){1,2})$

Podemos resumir em

^([\w.-_]+)@+[\w]+((.+\w{2,3}){1,2})$

Viu só como a utilização do RegEx é muito simples?

Agora neste ponto você já está habilitado a entender e construir suas próprias RegEx.

Se você não tem interesse no DART pode parar nesse ponto, pois falaremos especificamente dele agora.

Image description

Entre em nosso discord para interagir com a comunidade: https://discord.com/invite/flutterbrasil
https://linktr.ee/flutterbrasil

Top comments (0)