O estranho caso do Regex amaldiçoado
Neste artigo, você vai entender o básico das expressões regulares (Regex), como interpretar seus símbolos mais comuns e como utilizá-las em C# para validar padrões como e-mails, CEPs, telefones e senhas sem sucumbir à maldição do código indecifrável.
A pálida luz do monitor iluminando o rosto estático da Ermengarda no escritório escuro naquela madrugada, foi a última evidência de sua existência nesse mundo. Depois disso, apenas estática nas câmeras de segurança e o inexplicável desaparecimento da colaboradora.
A única pista deixada para trás foi um trabalho inacabado e um trecho de código que ninguém conseguia decifrar, com caracteres que mais pareciam runas ou símbolos arcanos, ou mesmo algum tipo de feitiçaria:
string padrao = @"^[\w\.-]+@[\w\.-]+\.\w+$";
Como esses estranhos caracteres estariam relacionados ao misterioso destino de Ermengarda?
Entendendo Expressões Regulares
Ocultismo digital à parte, essa sequência de caracteres é um exemplo típico do que chamamos de Expressão Regular (ou, para os íntimos, Regex), que nada mais são do que padrões usados para localizar, validar ou extrair informações de textos.
Na prática, são uma espécie de linguagem compacta para descrever padrões, sendo bastante utilizadas em cenários onde se necessita:
- Validar e-mails;
- Verificar senhas;
- Encontrar números em textos;
- Extrair informações de logs;
- Validar CEPs e telefones;
- Processar arquivos;
- Dentre outras.
O problema é que Regex possui uma sintaxe, no mínimo, peculiar e, para quem nunca teve contato com isso antes, parece menos programação e mais algum tipo de selo demoníaco encontrado em um livro proibido do século XIV.
Mas calma. Vamos decifrar esses símbolos estranhos.
Verbatim String
Antes de começarmos a explorar a estrutura das expressões regulares, é preciso chamar a atenção para um importante detalhe. Essa arroba colocada antes das aspas define uma string verbatim, que permite interpretar o texto exatamente como ele foi digitado, ignorando caracteres de escape (por exemplo \t ou \n), permitindo que a string ocupe várias linhas.
Um texto normal seria definido assim:
string normal = "Texto na primeira linha \nTexto na segunda linha";
Usando uma string verbatim, é possível escrever mais naturalmente:
string verbatim = @" Texto na primeira linha
Texto na segunda linha";
Parece insignificante, mas como em regex legibilidade é questão de sobrevivência, quanto menos caracteres de escape tivermos, menor a probabilidade de confusão entre o que é escape e o que é padrão de expressão regular.
Anatomia do Regex
Voltando ao computador da Ermengarda, temos aquele padrão incompreensível que inflige tanto temor à mente dos colaboradores supersticiosos:
@"^[\w\.-]+@[\w\.-]+\.\w+$"
Já posso adiantar que esse Regex é usado para validar e-mails simples (não cobre todas as regras possíveis de e-mails). Vamos então dissecar e entender esse padrão:
^ -> Indica o início da string, exatamente onde a expressão regular deve começar.
[] -> Indica um conjunto de caracteres
Então, no padrão [\w\.-]+ temos:
\w -> letras, números e _
. -> ponto
- -> hífen
+ -> significa “um ou mais”.
Assim, literalmente, estamos dizendo que nessa parte do padrão, devem ser aceitos blocos (conjuntos) de um ou mais caracteres que podem conter letras, números, underlines, pontos e hífens, representando o prefixo (ou nome de usuário) do e-mail.
nome-usuario
Avançando mais uma casa, encontramos @ que, quando
inserido no meio da cadeia, indica literalmente o caractere arroba
(nesse caso, a arroba do e-mail).
nome-usuario@
Logo em seguida, repete-se o padrão [\w\.-]+, então
a regra estabelece que após a arroba também podemos ter outro
conjunto de caracteres válidos para o domínio do e-mail.
nome-usuario@dominio
Complementando o domínio, seria preciso colocar um ponto, mas em
Regex, isso (.) representa qualquer caractere.
Dessa forma, é necessário usar o escape \.
nome-usuario@dominio.
Na sequência, o padrão \w+ informa que devem ser aceitos um ou mais caracteres contendo letras, números e underlines.
nome-usuario@dominio.tipo
Por fim, o caractere $ indica o fim da sequência
Regex (onde termina a regra).
Validando padrões com Regex
Com a regra acima, podemos verificar e decidir se um determinado e-mail é considerado válido (se obedece à regra estabelecida pela expressão regular).
using System;
using System.Text.RegularExpressions;
class Program
{
static void Main()
{
string padrao = @"^[\w\.-]+@[\w\.-]+\.\w+$";
string emailTestado = "nome@dominio.com.br";
// Validação direta retornando true ou false
bool ehValido = Regex.IsMatch(emailTestado, padrao);
if (ehValido)
{
Console.WriteLine("O e-mail é válido.");
}
else
{
Console.WriteLine("O e-mail é inválido.");
}
}
}
Resultados possíveis:
ermengarda-silva@gmail.com -> O e-mail é válido.
asdruballopes@tiburciosoft.com.br -> O e-mail é válido.
laurindo@outlook -> O e-mail é inválido. (não possui extensão do domínio)
otacilio@.com -> O e-mail é inválido. (não informou o conjunto de caracteres do domínio)
Outros exemplos de Regex
De forma análoga, as expressões regulares podem ser utilizadas para definir regras diversas para outros tipos de validações, como nos exemplos abaixo:
-
Validação de CEP:
@"^\d{5}-\d{3}$"– Aceita 5 números, seguido de hífen e mais 3 números. -
Validação de Telefone:
@"^\(\d{2}\)\s\d{4,5}-\d{4}$"– Aceita parêntesis com dois números, mais espaço (\s), mais uma sequência de 4 ou 5 números (\d), seguida de hífen e outra sequência de 4 números.
Quando a maldição do Regex se manifesta
Como quase tudo o que vem para esse mundo de Deus, as expressões regulares costumam nascer puras e inocentes, mas a ganância dos seres humanos rapidamente tende a corromper sua natureza gentil ao forçar que assumam o peso de grandes responsabilidades.
Nesse momento, dilaceradas e adoecidas por vibrações deletérias de pensamentos perturbados, elas pouco a pouco se transformam em maldições poderosas que atacam programadores incautos e inexperientes, podendo levar suas almas à loucura.
@"^(?=.*[A-Z])(?=.*\d)(?=.*[\W_]).{8,}$"
Na sequência acima, temos uma regra padrão para validação de senhas que, embora tecnicamente correta, já começa a ser psicologicamente perturbadora:
(?=.*[A-Z])-> pelo menos uma letra maiúscula(?=.*\d)-> pelo menos um número(?=.*[\W_])-> pelo menos um símbolo.{8,}-> mínimo de 8 caracteres
Quando usar Regex
De maneira geral, as expressões regulares (quando bem utilizadas) são excelentes recursos para redução de código, podendo ser aplicadas em:
- Validações simples;
- Extração de padrões;
- Processamento de logs;
- Parsing leve;
- Filtros textuais.
Quando NÃO usar Regex
Não é exatamente uma regra, mas uma sugestão baseada no bom senso: só porque expressões regulares conseguem resolver algo, não significa que deveriam. A não ser que você queira se expor perigosamente à maldição do Regex, seria prudente evitar seu uso para:
- Parsear HTML complexo;
- Interpretar linguagens inteiras;
- Regras extremamente difíceis de manter;
- Cenários onde clareza importa mais que compactação.
Se o Regex precisa de um ritual satânico para ser compreendido, talvez exista uma solução melhor.
Amuletos e encantamentos para se proteger da maldição
Dizem as lendas que alguns artefatos mágicos possuem o poder de proteção contra a maldição do Regex. Embora nenhum deles possa te manter totalmente imune, eles costumam aumentar a sua resistência e minimizar os danos dentro do possível:
Eles ajudam a:
- Visualizar grupos;
- Testar padrões;
- Entender o comportamento do Regex;
- Evitar invocar entidades desconhecidas acidentalmente.
Conclusão
Na manhã seguinte, a equipe finalmente conseguiu decifrar o padrão deixado por Ermengarda. Não era um ritual. Não era uma mensagem criptografada. Era apenas uma inocente validação de e-mail.
Ou pelo menos era o que parecia.
Coincidência ou não, nos meses e anos que se seguiram, diversos desenvolvedores que criaram ou deram manutenção em expressões regulares começaram a ouvir vozes e apresentar comportamentos estranhos.
Quanto à Ermengarda, nada mais se soube dela, mas dizem que seu espírito atormentado ainda vaga pela empresa atacando quem se aventura a programar Regex depois da meia-noite.