Vamos falar de RegEx?
Tags: regex, regularexpression, flutter, dart
Published: 2024-04-20 04:10:02

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

![](https://cdn-images-1.medium.com/max/800/1*5Y5d1WQWoplf4P7KDzxtQg.png)

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/](http://www.regexplained.co.uk/) nós teremos a explicação dessa expressão:

![](https://cdn-images-1.medium.com/max/800/1*CIlfKcc7fps_5hsXuasXUQ.png)

Também conseguimos fazer testes com o site [https://www.regexpal.com/](https://www.regexpal.com/)

![](https://cdn-images-1.medium.com/max/800/1*aLnS-l802uKIZVUVx_uhHw.png)

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

![](https://cdn-images-1.medium.com/max/800/1*witRtEQawRWacrcJniI0xg.png)

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

![](https://cdn-images-1.medium.com/max/800/1*ydkhca69C83o8I1HwnG4pQ.png)

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

![](https://cdn-images-1.medium.com/max/800/1*6NpPqAmUAqFIb4BtolR1MQ.png)

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:

![](https://cdn-images-1.medium.com/max/800/1*X4rHcODL8Xmoajj-XKZrYw.png)

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**

![](https://cdn-images-1.medium.com/max/800/1*2xD7KV1AJzBJ4_p8jjl50g.png)

Já **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**

![](https://cdn-images-1.medium.com/max/800/1*-IAfPUTOA7YftbReoSDMsw.png)

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).

![](https://cdn-images-1.medium.com/max/800/1*7r7alUlECGnauHvfJ9uSpg.png)

![](https://cdn-images-1.medium.com/max/800/1*YhIZgELIpegRm0eibgqdAQ.png)

![](https://cdn-images-1.medium.com/max/800/1*5MmgHqYpjJc_5i-KQNjVkg.png)

Eu também posso utilizar todos os ranges juntos

> **[A-Za-z0–9]**

![](https://cdn-images-1.medium.com/max/800/1*qVBqFTGqXfQCCCHJBGXJzw.png)

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

> **[À-é]**

![](https://cdn-images-1.medium.com/max/800/1*JbXWeiSBsdCi9mTD4IPyLQ.png)

### Quantificadores

![](https://cdn-images-1.medium.com/max/800/1*QLZLsVO1QqArEI9caXT08A.png)

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á:

![](https://cdn-images-1.medium.com/max/800/1*5bc_3OZYiJ4TjSE5hgjnDg.png)

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]***

![](https://cdn-images-1.medium.com/max/800/1*3pwa1EpXPSifzwp5Oq89wA.png)

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]+**

![](https://cdn-images-1.medium.com/max/800/1*9hiYjTsTL0q60D-ZIRN7_A.png)

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}

![](https://cdn-images-1.medium.com/max/800/1*3OJ-0LKd_NVzWeek6QucZQ.png)

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}**

![](https://cdn-images-1.medium.com/max/800/1*DYpG8y1YJkxA4_64pvwrXg.png)

### Âncoras

![](https://cdn-images-1.medium.com/max/800/1*gGiMRRqteiiQdYTSZx_ysg.png)

À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]+>$**

![](https://cdn-images-1.medium.com/max/800/1*Z7gnDozUBJUV7Hf4jkCjBw.png)

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**

![](https://cdn-images-1.medium.com/max/800/1*y5TZW6nkXiBB1lRPD-XMpQ.png)

### Outros

![](https://cdn-images-1.medium.com/max/800/1*Flv0AguAxvjsz4UXv5gGdw.png)

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}

![](https://cdn-images-1.medium.com/max/800/1*DYpG8y1YJkxA4_64pvwrXg.png)

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)**

![](https://cdn-images-1.medium.com/max/800/1*CRF_j5hIi0IJyFZcfh2YfQ.png)

### 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}**

![](https://cdn-images-1.medium.com/max/800/1*FSkzwgNDH_8__H_leqA0Sg.png)

Poderíamos resumir em

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

![](https://cdn-images-1.medium.com/max/800/1*NS2wwZh82jowio-M5U7o1g.png)

**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

![](https://cdn-images-1.medium.com/max/800/1*tWKdWCGOPaOm8QoOrvL1yg.png)

### 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]+)>**

![](https://cdn-images-1.medium.com/max/800/1*tbv_2XSut_98dfITMocfPw.png)

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

![](https://cdn-images-1.medium.com/max/800/1*ZSxe-7E7bdohIfgK_r9kug.png)

![](https://cdn-images-1.medium.com/max/800/1*ujLrs0zgbtY7hZpFZ02BWg.png)

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

![](https://cdn-images-1.medium.com/max/800/1*wd-E8wMstHUlxcSLg09Y3Q.png)

### 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

![](https://cdn-images-1.medium.com/max/800/1*_aENz2sC_ge4PjxkSsybBQ.png)

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

![](https://cdn-images-1.medium.com/max/800/1*gBpiNmvFrTUlm4RYvTABZg.png)

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}

![](https://cdn-images-1.medium.com/max/800/1*Sc6eQ2bfmKOTo_s71jJMug.png)

Podemos simplificar e obteremos o mesmo resultado

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

![](https://cdn-images-1.medium.com/max/800/1*fo3LgYQSXLXa494t9FfFLw.png)

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})$

![](https://cdn-images-1.medium.com/max/800/1*Ci1NS-fiZIie2_PHFpYc8Q.png)

Podemos resumir em

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

![](https://cdn-images-1.medium.com/max/800/1*10rsxZs3N2CTuZkbekdAcQ.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/obcg0d2y00yddve9quky.png)


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