Validando dados com Regex
Tags: regex, javascript, programming, webdev
Published: 2023-02-06 15:07:29

**Expressões Regulares**, em inglês Regular Expression (Regex), nada mais são do que **padrões para validação ou captura de informações**. Em outras palavras, é um recurso muito poderoso e útil para manipular dados.

## Estudo de caso simples
Nada melhor do que aprender algo na prática, não é mesmo? Pensando nisso, tive a ideia de fazermos uma validação de e-mails, assim conseguiremos pôr em prática alguns recursos que uma **regex** oferece.

Os códigos abaixo serão feitos com JavaScript, pois acho que vai ser mais simples de explicar e de praticar, vocês podem utilizar o console do navegador para executar os códigos.
```js
// Primeiramente vamos definir uma variável que contenha um e-mail qualquer
let email = 'erandirjunior@email.com';
```

Agora com a ajuda do método __match__, iremos criar nossa primeira expressão, e validar se o dado informado atende o nosso padrão:
```js
/*
Em JS podemos definir uma expressão regular de forma literal ou pelo uso do objeto RegExp.
Nos exemplos utilizarei a forma literal, bastando definir a expressão por meio do //.

O código abaixo vai retornar um array contendo algumas informações,
caso nossa verificação falhasse, receberíamos null como retorno
*/
email.match(/erandirjunior@email.com/);
```

Para primeira validação, não temos nada complicado, passamos basicamente o mesmo valor contido na nossa variável **email**. A partir de agora vamos deixar nossa expressão mais genérica e ver o quão poderoso e útil pode ser uma **regex**.

Um recurso interessante que podemos utilizar é o metacaractere **\w**, ele serve para representar uma **letra, número e o underline**, vejam abaixo:
```js
email.match(/\w\w\w\w\w\w\w\w\w\w\w\w\w@email.com/);
// Obtemos o mesmo resultado que o código anterior
```
Só reforçando, o metacaractere **\w** substitui letras de **a-z, A-Z e números de 0-9 e o caractere _**.

O exemplo acima não tá legal pois estamos sendo repetitivos, vamos melhorar nosso código informando que determinado caractere pode se repetir uma quantidade específica de vezes:
```js
email.match(/\w{13}@email.com/);
```
Acima informamos que um caractere - dentro da regra explicada anteriormente - deve aparecer no mínimo e no máximo 13 vezes.

Nosso padrão até então aceita letras, números e _ no início do nosso e-mail, vamos informar que também podemos aceitar **.**, para isso vamos fazer uso de um agregador de caracteres, vejam:
```js
email.match(/[a-zA-Z0-9._]{13}@email.com/);
```
Podemos agrupar caracteres por meio do _[]_, e dentro colocamos tudo o que é aceito. Em nosso caso, informamos que é aceito exclusivamente letras de a até z minúsculas, letras de A até Z maiúsculas, números, o ponto e o underline. Outro ponto a se destacar, é que a ordem do caracteres não importa, então poderíamos ter um e-mail iniciando com . ou _ por exemplo.

Continuando, nossa validação passou, porém, se passarmos um e-mail diferente, com caracteres a menos ou a mais, teremos comportamentos estranhos, executem o código abaixo e notem o retorno:
```js
'erandir.junior@email.com'.match(/[a-zA-Z0-9._]{13}@email.com/);
// Verifiquem o conteúdo do retorno e vejam que foi ignorado a primeira letra
```

Para corrigir isso, podemos fazer de duas formas, a primeira é informar uma quantidade mínima e deixar a máxima em aberto:
```js
// O valor mínimo aceito é de 1 caractere e não temos valor máximo, mas podemos definir.
email.match(/[a-zA-Z0-9._]{1,}@email.com/);

'erandir.junior@email.com'.match(/[a-zA-Z0-9._]{1,}@email.com/);
```

Já a segunda forma de corrigir é substituir o quantificador __{}__, por __+__:
```js
email.match(/[a-zA-Z0-9._]+@email.com/);

'erandir.junior@email.com'.match(/[a-zA-Z0-9._]+@email.com/);
```

A grande diferença entre eles, é que o quantificador __+__ informa que um caractere ou mais deve existir, já no quantificador __{}__, podemos definir uma quantidade fixa, apenas a mínima ou a quantidade mínima e máxima.

Até aqui estamos indo bem, agora vamos trabalhar em cima do host do e-mail, aquela parte depois do __@__:
```js
email.match(/[a-zA-Z0-9._]+@[a-zA-Z0-9]+.com/);
```

Existem e-mails que contém o identificador do país, por exemplo e-mails que terminam em _.com.br_. No código abaixo, vamos informar que o _.algumacoisa_, após o _.com_, é completamente opcional:
```js
email.match(/[a-zA-Z0-9._]+@[a-zA-Z0-9._]+.com(?:.[a-z]+)?/);
```
Explicando de forma mais detalhada a modificação realizada:
- Primeiramente envolvemos um código em um grupo de captura por meio de __()__, veremos isso mais detalhadamente em outro artigo;
- Em segundo lugar, informamos que não queremos capturar o grupo, isso por meio do __?:__;
- Depois informamos que os caracteres aceitos são o _._ e obrigatoriamente depois um conjunto de caracteres, neste caso, de __a até z__, sendo no mínimo 1 caractere;
- E por último, Utilizando o __?__, informamos que um caractere, grupo, etc, é opcional. No nosso caso, todo o grupo é opcional.

Espero que tenham entendido até aqui, mesmo assim, vai ficar muito mais claro com outros exemplos.

Até aqui passamos de uma validação fixa para uma dinâmica. Agora vamos adicionar mais uma regra, particularmente quando me cadastro em um site, costumo adicionar algo no e-mail que me permita identificar esse e-mail posteriormente como único, em outras palavras, posso me cadastrar assim: _erandirjunior+teste@email.com_. Onde o _+teste_, por exemplo, poderia ser o nome do site, ou algo do tipo. Vamos aplicar essa regra em nosso código:
```js
email.match(/[a-zA-Z0-9._]+(?:\+[a-zA-Z0-9._]+)?@[a-zA-Z0-9._]+.com(?:.[a-z]+)?/);

'erandir.junior@email.com'.match(/[a-zA-Z0-9._]+(?:\+[a-zA-Z0-9._]+)?@[a-zA-Z0-9._]+.com(?:.[a-z]+)?/);

'erandir.junior@email.com.br'.match(/[a-zA-Z0-9._]+(?:\+[a-zA-Z0-9._]+)?@[a-zA-Z0-9._]+.com(?:.[a-z]+)?/);

'erandir.junior+teste@email.com.br'.match(/[a-zA-Z0-9._]+(?:\+[a-zA-Z0-9._]+)?@[a-zA-Z0-9._]+.com(?:.[a-z]+)?/);
```
O detalhe dos códigos acima ficam por conta da necessidade de escapar o caractere _+_, para que não seja entendido como um quantificador e sim como um caractere comum.

Calma que não paramos por aqui, quero explicar mais uma coisa, digamos que a string que contenha o e-mail venha com um espaço no início ou fim. Isso pode ser um problema, então vamos informar que o dado que vier tem que obrigatoriamente iniciar e terminar com nossa validação, para isso basta adicionar os caracteres __^__ no início e __$__ no final:
```js
email.match(/^[a-zA-Z0-9._]+(?:\+[a-zA-Z0-9._]+)?@[a-zA-Z0-9._]+.com(?:.[a-z]+)?$/);

// Isso não funciona
' erandir.junior@email.com'.match(/^[a-zA-Z0-9._]+(?:\+[a-zA-Z0-9._]+)?@[a-zA-Z0-9._]+.com(?:.[a-z]+)?$/);

// Isso não funciona
'erandir.junior@email.com.br '.match(/^[a-zA-Z0-9._]+(?:\+[a-zA-Z0-9._]+)?@[a-zA-Z0-9._]+.com(?:.[a-z]+)?$/);

// Funciona
'erandir.junior+teste@email.com.br'.match(/^[a-zA-Z0-9._]+(?:\+[a-zA-Z0-9._]+)?@[a-zA-Z0-9._]+.com(?:.[a-z]+)?$/);
```

Gostaria de lembrar que definimos uma regra onde aceitamos letras, números, ponto e undeline na primeira parte de um e-mail, porém, isso não impede de termos . ou _ como primeiro caractere, então vamos definir uma regra, na qual o primeiro caractere só pode ser letra, e o caractere seguinte pode ser qualquer outro.
```js
email.match(/^[^0-9._][a-zA-Z0-9._]+(?:\+[a-zA-Z0-9._]+)?@[a-zA-Z0-9._]+.com(?:.[a-z]+)?$/);
```
Pode parecer confuso, e realmente é, não vou mentir pra vocês, mas com calma vocês vão entender: lembrando que dentro de _[]_ nós definimos o que é aceito, e que _^_ no começo de uma regex, informa que a string a ser manipulada deve iniciar exatamente com as regras definidas no padrão, porém, quando utilizamos o ^ dentro do agrupador _[]_, dizemos que tudo definido dentro de _[]_, não é aceito. Viram como não é complicado?

Um último ponto que gostaria de falar, é sobre o host de um e-mail, digamos que agora só vamos validar e-mails com host _xpto_ ou _ywz_, então podemos alterar um pouco a nossa regra, veja abaixo:
```js
// Aqui vai falhar pois nosso e-mail tem o host diferente do aceito
email.match(/^[^0-9._][a-zA-Z0-9._]+(?:\+[a-zA-Z0-9._]+)?@(?:xpto|xwz).com(?:.[a-z]+)?$/);

// Aqui vai funcionar pois nosso host é um dos aceitos
'erandir.junior@xpto.com.br'.match(/^[^0-9._][a-zA-Z0-9._]+(?:\+[a-zA-Z0-9._]+)?@(?:xpto|xwz).com(?:.[a-z]+)?$/);
```

## Dica
Um site muito útil e que utilizo sempre que vou definir uma regex, é o https://regex101.com/, nele eu consigo testar regex, ver os recursos disponíveis e ainda exportar o código para a linguagem de programação que utilizo, vejam a imagem a seguir para maiores detalhes:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x7jytavtq3mwrff8ovuy.png)


## Finalizando
Neste artigo pude mostrar alguns recursos bem úteis que uma expressão pode oferecer, acredito que apesar de não vermos tudo que uma regex oferece, com os recursos mostrados, pode-se fazer a validação de outras coisas, bastando adaptar os exemplos mostrados acima. Nos próximos artigos veremos outras funcionalidades, vejo você por lá, até mais.