1001Ferramentas
🔍 Dev

Expressões regulares do zero: um guia prático para iniciantes

O que é uma regex e onde ela vive, os metacaracteres essenciais, grupos e capturas, padrões prontos e os erros que tornam a regex lenta.

Atualizado em 30 de junho de 2026 · 9 min de leitura

O que é uma regex e onde ela vive

Uma expressão regular (ou regex) é uma pequena linguagem para descrever padrões de texto. Em vez de procurar a palavra exata "gato", você descreve uma regra — "três dígitos, um traço, mais quatro dígitos" — e o motor de regex encontra tudo que se encaixa. É a diferença entre apontar para uma coisa e descrever uma família inteira de coisas.

Você já cruzou com regex sem saber. Ela está no "Localizar e substituir" avançado do VS Code, no comando grep do terminal, na validação daquele formulário que reclamou do seu e-mail, e em praticamente toda linguagem de programação: JavaScript, Python, PHP, Java, Go. A sintaxe é quase a mesma em todas porque a maioria descende do mesmo avô, o Perl (daí o nome PCRE, Perl Compatible Regular Expressions).

Na prática, uma regex faz três coisas: testar se um texto bate com o padrão (verdadeiro ou falso), extrair os pedaços que interessam e substituir o que casou por outra coisa. O melhor jeito de aprender é experimentando: cole um padrão e um texto no Testador de Regex e veja, em tempo real, o que acende e o que não acende.

Os metacaracteres essenciais

A maior parte dos caracteres em uma regex representa a si mesma: o padrão casa casa com a palavra "casa". A mágica vem dos metacaracteres, símbolos com significado especial. Estes são os que você usa 90% do tempo:

SímboloSignificaExemplo
.qualquer caractere (menos quebra de linha)c.sa → casa, cosa, c8sa
\dum dígito de 0 a 9\d\d → 42
\wletra, dígito ou _ (sem acento!)\w+ → palavra1
\sespaço, tab ou quebra de linhaa\sb → "a b"
\D \W \So oposto de cada um acima\D → não-dígito

Um detalhe que pega todo brasileiro: \w equivale a [A-Za-z0-9_] e não inclui letras acentuadas. Em "João", o "ã" não é considerado \w. Para capturar palavras em português, ou você lista os acentos à mão ([A-Za-zÀ-ÿ]) ou usa o modo Unicode com propriedades, como \p{L} e a flag u.

Quando você precisa do significado literal de um metacaractere, coloque uma barra invertida na frente. Para casar um ponto de verdade — em "arquivo.pdf" —, escreva \., não . (que casaria com qualquer caractere).

Classes, quantificadores e âncoras

Classes de caracteres

Os colchetes criam um conjunto: case com qualquer um dos caracteres dentro deles. [aeiou] casa uma vogal; [a-z] usa um intervalo; [0-9A-F] casa um dígito hexadecimal. Um circunflexo logo após o colchete inverte tudo: [^0-9] casa qualquer coisa que não seja dígito.

Quantificadores

Sozinho, um padrão casa uma ocorrência. Os quantificadores dizem quantas vezes repetir o que vem antes:

  • ? — zero ou uma vez (opcional)
  • * — zero ou mais vezes
  • + — uma ou mais vezes
  • {3} — exatamente 3; {2,4} — de 2 a 4; {2,} — 2 ou mais

Então \d{5}-?\d{3} lê "cinco dígitos, um traço opcional, três dígitos". Por padrão os quantificadores são gananciosos (greedy): pegam o máximo que conseguem. Em <b>oi</b>, o padrão <.*> casa a linha inteira, não só a primeira tag. Acrescentar um ? torna o quantificador preguiçoso (lazy): <.*?> para na primeira ocorrência possível.

Âncoras

Âncoras não casam caracteres — casam posições. O ^ marca o início do texto e o $ marca o fim. Eles são o que separa "validar" de "encontrar". Sem âncoras, \d{3} aceita "abc123def" porque existe uma sequência de três dígitos lá dentro. Com ^\d{3}$, o texto inteiro precisa ser exatamente três dígitos. O \b marca uma fronteira de palavra, útil para casar a palavra isolada e não como parte de outra.

Grupos e capturas

Os parênteses fazem duas coisas ao mesmo tempo: agrupam um trecho para aplicar um quantificador a ele e capturam o que casou para você reaproveitar depois. Em (ha)+, o + repete o grupo inteiro, casando "ha", "haha", "hahaha".

O uso clássico é extrair pedaços. Tome o padrão (\d{2})/(\d{2})/(\d{4}) aplicado a "30/06/2026". Ele cria três grupos: o grupo 1 vira "30", o 2 vira "06" e o 3 vira "2026". Numa substituição, você se refere a eles por $1, $2, $3. Substituir por $3-$2-$1 transforma a data brasileira "30/06/2026" no formato ISO "2026-06-30" em uma linha.

Variações úteis: (?:...) agrupa sem capturar (mais rápido e mantém a numeração limpa quando você só precisa do quantificador); (?<ano>\d{4}) dá um nome ao grupo, e você o acessa por ano em vez de contar parênteses; e a barra vertical | é o "ou": (jpg|png|gif) casa qualquer uma das três extensões.

Padrões prontos: e-mail, CEP e telefone

Com o vocabulário acima, dá para montar os padrões que mais aparecem no dia a dia. Use o Testador de Regex para colar cada um e ver casando.

O quêPadrãoCasa
CEP^\d{5}-?\d{3}$01310-100 / 01310100
Telefone com DDD^\(\d{2}\)\s?9?\d{4}-?\d{4}$(11) 98765-4321
E-mail (pragmático)^[^\s@]+@[^\s@]+\.[^\s@]+$[email protected]

Repare no padrão de e-mail. Ele não tenta listar todos os domínios do mundo; só exige "algo, um arroba, algo, um ponto, algo", sem espaços. Tentativas de criar a regex "perfeita" de e-mail produzem monstros de centenas de caracteres que ainda assim erram casos válidos. Para a maioria dos formulários, o padrão simples acima já filtra os erros de digitação grosseiros — e a validação de verdade é mandar um e-mail de confirmação. Se quiser uma checagem mais robusta sem montar a regex à mão, o Validador de Email faz esse trabalho.

Regex também serve para limpar texto, não só validar. Para gerar um slug de URL a partir de um título, o passo central é substituir tudo que não for letra ou número por um hífen: [^a-z0-9]+- (depois de remover acentos e baixar a caixa). É exatamente isso que o Slugify faz: "Olá, Mundo!" vira "ola-mundo".

Erros que travam ou tornam a regex lenta (backtracking)

Regex é poderosa, mas tem armadilhas. Quatro causam quase toda dor de cabeça:

  1. Esquecer de escapar o ponto. Validar "site.com" com site.com aceita também "siteXcom", porque o . casa qualquer caractere. Use site\.com.
  2. Validar sem âncoras. Sem ^ e $, "12345abc" passa numa regra que deveria aceitar só "12345".
  3. Ser ganancioso demais. .* costuma engolir mais do que você queria; troque por uma versão preguiçosa .*? ou por uma classe específica.
  4. Backtracking catastrófico. O erro mais perigoso, porque pode congelar o programa.

O backtracking acontece quando o motor precisa testar muitas combinações para decidir se algo casa. Quantificadores aninhados são a receita do desastre. Veja ^(\d+)+$ aplicado a uma string longa de dígitos terminada por uma letra, como "99999999999999999999X". Como o "X" nunca vai casar com $, o motor tenta repartir os dígitos entre o + de dentro e o de fora de todas as maneiras possíveis antes de desistir — um número exponencial de tentativas. Com 25 dígitos, isso já pode levar segundos; com 40, trava. A correção é simples: ^\d+$ faz o mesmo trabalho sem aninhar.

Esse problema tem até nome de segurança: ReDoS (Regular expression Denial of Service). Uma regex mal construída em um servidor pode ser derrubada por um único texto malicioso. A defesa é evitar quantificadores aninhados ((a+)+, (.*)*), preferir classes específicas a .* e sempre testar com entradas longas no Testador de Regex antes de subir para produção.

Perguntas frequentes

A regex é igual em todas as linguagens?

Quase. O núcleo — metacaracteres, quantificadores, grupos — é o mesmo em JavaScript, Python, PHP, Java e na maioria das ferramentas. As diferenças aparecem nos recursos avançados: o JavaScript ganhou lookbehind e grupos nomeados só em 2018, e não tem quantificadores possessivos nem grupos atômicos como o PCRE. Para padrões do dia a dia, o que você aprende aqui vale em todo lugar.

Como faço uma busca ignorando maiúsculas e minúsculas?

Use a flag i (de insensitive). Em JavaScript, /casa/i casa "Casa", "CASA" e "casa". Outras flags úteis: g (encontrar todas as ocorrências, não só a primeira) e m (faz ^ e $ valerem por linha).

Posso usar regex para validar e-mail de forma definitiva?

Não existe regex que aceite exatamente todos os e-mails válidos e rejeite todos os inválidos — a especificação é cheia de exceções. Use um padrão simples para barrar erros óbvios de digitação e confirme o endereço de verdade enviando uma mensagem. A validação por regex é o porteiro, não a prova final.

Dá para analisar HTML com regex?

Para tarefas pontuais (achar todos os href, por exemplo), funciona. Para realmente entender a estrutura de um documento, não: HTML pode aninhar de formas que uma regex não consegue acompanhar. Aí o caminho é um parser de verdade. Regex brilha em texto "plano" com padrões locais; documentos com hierarquia pedem outra ferramenta.

Qual a diferença entre greedy e lazy?

Greedy (padrão) pega o máximo de caracteres possível e depois "devolve" se precisar; lazy (com ? depois do quantificador) pega o mínimo e só estende se for obrigada. Em "<a><b>", <.*> casa tudo, enquanto <.*?> casa só "<a>". Escolher o certo evita capturar texto demais.

Ferramentas citadas neste guia

Continue lendo