Artigo Build·Desenvolvimento·14 min de leitura de leitura

Expressões Regulares (Regex): Guia Completo 2026 com Exemplos Práticos

Regex é uma das habilidades com maior ROI na carreira de desenvolvimento: aprender os fundamentos em algumas horas economiza centenas de linhas de código ao longo do tempo. Este guia cobre do metacaractere básico ao lookbehind, com exemplos prontos em JavaScript e Python.

Vitor Morais

Por Vitor Morais

Fundador do MochaLabz ·

🧪

Teste regex em tempo real

Cole o padrão, cole o texto e veja os matches destacados na hora.

Usar testador →

Expressões regulares, ou regex, são um mini-idioma para descrever padrões em texto. Com uma única expressão você busca, valida, substitui e extrai dados de qualquer tipo de string — de logs de servidor a formulários web, de CSVs mal formatados a código-fonte. É conhecimento que, uma vez instalado na cabeça, acompanha você em qualquer linguagem e qualquer editor pelo resto da carreira.

A fama de “esotérico” vem de tutoriais que despejam 50 símbolos na primeira página. Ignorado isso, regex é pequeno e lógico. Este guia constrói do fundamento até técnicas avançadas (lookaround, grupos nomeados, backreferences), sempre com caso real.

O modelo mental: regex como linguagem de busca

Uma regex é um padrão. Quando aplicada a um texto, o engine percorre caractere por caractere tentando casar o padrão. Se casa, retorna o match; se não, segue adiante. Três operações básicas se constroem sobre esse mecanismo:

  • Teste: o texto contém o padrão?
  • Extração: quais partes do texto casam com o padrão?
  • Substituição: troque o que casou por outra coisa.

Toda regex que você vai escrever cai em uma dessas três categorias.

Caracteres literais e metacaracteres

Letras e números em regex casam consigo mesmos. gato bate com “gato” em qualquer texto. Os metacaracteres são os que têm significado especial:

Principais metacaracteres
CritérioSignificadoExemplo
.Qualquer caractere (exceto quebra de linha)c.sa bate com casa, cosa, cxsa
^Início de linha/string^abc bate com linha que começa em abc
$Fim de linha/stringxyz$ bate com linha que termina em xyz
\dDígito (0-9)\d\d bate 42, 07, 99
\wLetra, número ou _\w+ bate palavras
\sEspaço em brancoa\sb bate 'a b' ou 'a\tb'
\D \W \SNegações de \d \w \s\D bate qualquer não-dígito
\bBorda de palavra\bfoo\b bate foo isolado

Classes de caracteres

Dentro de [] você lista caracteres aceitos. Dentro do colchete, a maioria dos metacaracteres perde o sentido especial.

  • [abc] bate com a, b ou c.
  • [a-z] bate com qualquer letra minúscula.
  • [A-Za-z0-9] bate com letras e números.
  • [^abc] bate com qualquer coisa que não seja a, b ou c (negação com ^ no início).
// JavaScript: extrair apenas números de um texto const texto = "Pedido #4823 foi aprovado com valor R$ 1250."; const numeros = texto.match(/\d+/g); // ["4823", "1250"] // Python equivalente import re re.findall(r"\d+", "Pedido #4823 foi aprovado com valor R$ 1250.") # ['4823', '1250']

Quantificadores: quantas vezes o padrão repete

Quantificadores e seus significados
CritérioSignificaExemplo
?0 ou 1 vez (opcional)colou?r bate color e colour
*0 ou mais vezesa* bate vazio, a, aa, aaa...
+1 ou mais vezes\d+ bate 1, 42, 99999
{n}Exatamente n vezes\d{4} bate 4 dígitos seguidos
{n,}n ou mais vezes\d{3,} bate 3+ dígitos
{n,m}Entre n e m vezes\d{2,4} bate 2 a 4 dígitos

Atenção

Quantificadores são greedy por padrão — capturam o máximo possível. Para tornar lazy, acrescente ?: .*?, \d+?. A diferença entre <.*> e <.*?> em HTML é o bug mais famoso de regex do mundo.

Alternação e grupos

A barra vertical | funciona como “ou”. Parênteses () agrupam partes do padrão e também criam grupos de captura.

// Alternação: casa com gato ou cachorro /gato|cachorro/ // Agrupar para aplicar quantificador em bloco inteiro /(ab)+/ // ab, abab, ababab // Captura: parênteses criam grupos acessíveis const match = "João nasceu em 1985".match(/(\w+).*?(\d{4})/); // match[1] === "João" // match[2] === "1985" // Non-capturing group: agrupa sem guardar /(?:ab)+/ // agrupa para o +, mas não cria grupo

Grupos nomeados e backreferences

Em padrões complexos, nomear grupos torna o código muito mais legível:

// Grupo nomeado (JavaScript ES2018+) const match = "2026-04-17".match( /(?<ano>\d{4})-(?<mes>\d{2})-(?<dia>\d{2})/ ); // match.groups.ano === "2026" // match.groups.mes === "04" // match.groups.dia === "17" // Backreference: referencia grupo já capturado // Detecta palavras duplicadas: /(\b\w+) \1/ // bate "o o", "muito muito", "bem bem"

Dica

Em substituições, referencie grupos com $1, $2 ou $<nome> (para grupos nomeados). Útil para reformatar datas: 2026-04-1717/04/2026 em uma linha.

Lookahead e lookbehind

Lookaround testa se algo vem antes ou depois sem consumir o match. Útil para capturar “X que vem antes de Y” ou “Z que não é seguido por W”.

Tipos de lookaround
CritérioSintaxeSignifica
Positive lookahead(?=...)o match precisa ser seguido por ...
Negative lookahead(?!...)o match NÃO pode ser seguido por ...
Positive lookbehind(?<=...)o match precisa ser precedido por ...
Negative lookbehind(?<!...)o match NÃO pode ser precedido por ...
// Extrair preço em reais (número seguido de "reais" sem // capturar a palavra "reais") const texto = "Custa 120 reais e vale 200 reais"; texto.match(/\d+(?= reais)/g); // ["120", "200"] // Capturar @username em menções, sem o @ "oi @joao e @maria".match(/(?<=@)\w+/g); // ["joao", "maria"] // Senhas que têm maiúscula, minúscula, número e 8+ chars const forte = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/;

Flags: o comportamento global

  • g (global): encontra todos os matches, não só o primeiro.
  • i (insensitive): ignora maiúsculas e minúsculas.
  • m (multiline): faz ^ e $ casarem início e fim de linha, não só da string inteira.
  • s (dotall): faz . bater também em quebras de linha.
  • u (unicode): suporta escapes unicode e grupos de propriedade.
  • y (sticky, JavaScript): match ancorado na posiçãolastIndex.

Padrões prontos para copiar

E-mail simples (80% dos casos)

/^[\w.+-]+@[\w-]+\.[\w.-]+$/

URL (http/https)

/https?:\/\/[\w.-]+(?:\.[\w.-]+)+[\w\-._~:/?#[\]@!$&'()*+,;=%]*/

Telefone brasileiro (celular e fixo)

/^\(?\d{2}\)?[\s-]?\d{4,5}[\s-]?\d{4}$/

CPF com ou sem pontuação

/^\d{3}\.?\d{3}\.?\d{3}-?\d{2}$/

CEP brasileiro

/^\d{5}-?\d{3}$/

Data ISO (YYYY-MM-DD)

/^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])$/

Senha forte (8+ chars, maiúscula, minúscula, número)

/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/

Aplicação prática em JavaScript

const regex = /\d+/g; const texto = "Pedido 42 e pedido 107"; // Teste regex.test(texto); // true // Extração texto.match(regex); // ["42", "107"] [...texto.matchAll(regex)]; // array com índices // Substituição texto.replace(regex, "N"); // "Pedido N e pedido N" // Split "um,dois;tres quatro".split(/[,;\s]+/); // ["um", "dois", "tres", "quatro"]

Aplicação em Python

import re texto = "Pedido 42 e pedido 107" # Teste bool(re.search(r"\d+", texto)) # True # Extração re.findall(r"\d+", texto) # ['42', '107'] # Iteração com objetos match for m in re.finditer(r"\d+", texto): print(m.group(), m.start(), m.end()) # Substituição re.sub(r"\d+", "N", texto) # "Pedido N e pedido N" # Compilar uma vez, usar várias (mais rápido em loop) padrao = re.compile(r"\d+") padrao.findall(texto)

Erros clássicos que geram bug em produção

  • Greedy onde devia ser lazy: <.*> em HTML captura tudo; use <.*?>.
  • Esquecer ancoragem: validar CPF sem ^ e $ aceita 123.456.789-00 lixo extra.
  • Usar . achando que exclui quebras: em flag s ou em alguns engines, casa com qualquer coisa.
  • Não testar input vazio: regex com * pode match string vazia.
  • Não escapar caracteres especiais em valor dinâmico: construir regex com input do usuário é vetor de ReDoS.
  • Ignorar unicode: \w em JavaScript só bate ASCII. Use \p{L} com flag u para letras acentuadas.

Performance: quando regex fica lenta

Regex é rápida para a maioria dos casos, mas algumas construções são armadilha:

  • Backtracking catastrófico: padrões com quantificadores aninhados ((.+)+) em input grande travam o engine.
  • Alternação mal ordenada: (a|ab|abc) é mais lenta que(abc|ab|a) porque o engine tenta matches em ordem.
  • Regex compilada a cada iteração: em Python e JavaScript, se você usa a mesma regex em loop, compile uma vez fora.

Vai mais fundo

Em produção web, sempre valide o tamanho do input antes de aplicar regex complexa. Um input de 10KB em um padrão vulnerável a ReDoS pode prender um worker Node por segundos, abrindo vetor de DoS. Vale, em rotas públicas, limitar o input a 1–2KB.

Quando regex é a ferramenta errada

  • Parsear HTML, XML ou JSON — sempre use parser dedicado.
  • Cálculo de validação (CPF, cartão de crédito) — regex vê formato, não aritmética.
  • Buscas triviais de substring — includes ou indexOf é mais legível.
  • Lógica de negócio complexa — 50 alternações num único regex é manutenção impossível.

Estratégia para escrever regex que dura

  1. Comece escrevendo em prosa: “4 dígitos, hífen, 2 dígitos, hífen, 2 dígitos”.
  2. Traduza bloco a bloco: \d{4}-\d{2}-\d{2}.
  3. Teste com 3 inputs: válido típico, válido edge, inválido.
  4. Cole no regex101, leia a explicação gerada. Se não bate com o que você queria, refaça.
  5. Adicione ancoragem e refine progressivamente.
  6. Comente o regex no código — um regex complexo sem comentário é sempre dívida técnica.

Regex em uma frase

Expressões regulares são um investimento raro em dev: algumas horas de estudo rendem décadas de produtividade, em qualquer linguagem, qualquer editor, qualquer linha de comando. Aprenda os 20 metacaracteres essenciais, domine os quantificadores, entenda grupos — e o resto é só composição.

Perguntas frequentes

Regex é a mesma coisa em JavaScript, Python, PHP e outras linguagens?+

O núcleo é igual: metacaracteres, quantificadores, classes e grupos seguem a mesma gramática. As diferenças estão nas flags (JavaScript usa /g, Python usa re.MULTILINE), no suporte a recursos avançados (PHP e Python têm lookbehind variável; JavaScript até 2018 não tinha lookbehind) e na sintaxe para acessar grupos. 90% do que você aprende em uma linguagem se aplica em qualquer outra.

Quando não usar regex?+

Para parsear HTML, JSON, XML ou qualquer formato com estrutura aninhada. Regex não reconhece hierarquia recursiva — use o parser dedicado (DOMParser, JSON.parse, libxml). Para validação de e-mail rigorosa, use a biblioteca da linguagem (ex.: email-validator em Python), que implementa RFC 5322 corretamente. Para busca simples em texto pequeno, indexOf ou includes é mais legível.

Qual a diferença entre .* e .*?+

O .* é greedy (ganancioso): captura o maior match possível. O .*? é lazy (preguiçoso): captura o menor match possível. Em texto <b>um</b> <b>dois</b>, o padrão <b>.*</b> captura tudo de uma vez; <b>.*?</b> captura cada bloco separadamente. 90% dos bugs de regex vêm de confundir os dois.

Preciso escapar barras, parênteses e outros caracteres especiais?+

Sim, quando você quer que o caractere apareça literal e não como metacaractere. Para cuidar dos comuns, escape com barra invertida: \. \( \) \? \+ \*. Dentro de classes [], a maioria dos metacaracteres perde o sentido especial e não precisa escapar — exceção: ], \ e, em algumas posições, - e ^.

O que é ReDoS e como evitar?+

Regex Denial of Service é ataque em que um regex mal escrito trava o servidor. Acontece com padrões catastróficos como (a+)+$ rodando em input aaaaaaaaaaX — o engine tenta bilhões de combinações. Evitar: desconfie de quantificadores aninhados, use possessive quantifiers ou atomic groups quando disponíveis, valide tamanho máximo do input antes de aplicar regex, e prefira regex simples a virtuosismo.

Qual ferramenta usar para testar regex antes de colocar em produção?+

Regex101.com é o padrão da indústria. Mostra explicação em tempo real, destaca matches, simula todas as flags, tem debugger passo a passo e permite salvar. Alternativas: Regexr (mais leve), regexper.com (gera diagrama visual do padrão). Sempre teste com pelo menos 3 casos: input típico, input vazio e input malicioso/extremo.

É possível fazer regex case-insensitive?+

Sim. Em JavaScript e PCRE, adicione a flag i: /hello/i bate com HELLO, Hello, hello. Em Python, passe re.IGNORECASE como segundo argumento. Também dá para usar inline modifiers: (?i)hello ativa case-insensitive dentro do próprio padrão, o que é útil quando você não controla o compile flags.

Regex substitui validação de negócio como CPF e CNPJ?+

Parcialmente. Regex valida o formato (tamanho, separadores, tipo de caractere), mas não o algoritmo do dígito verificador. Para CPF e CNPJ brasileiros, o regex filtra entrada inválida na UI, mas a validação final exige função que calcula módulo 11 e compara com os dois últimos dígitos. Use regex como primeira barreira e o algoritmo como confirmação.

#regex#expressões regulares#javascript#python#metacaracteres#quantificadores#lookahead#lookbehind#validação

Artigos relacionados