Python: Expressões Regulares
Última atualização: 2026-09-22
Uma expressão regular (regex) é uma linguagem especial para descrever padrões de texto. Uma linha de regex pode fazer o que dezenas de linhas de código manual levariam para corresponder e extrair texto. Está em toda parte na limpeza de dados, análise de log e validação de formulários.
1. O que é uma Expressão Regular
Uma expressão regular usa símbolos especiais para descrever "que tipo de string estou procurando."
import re
# Regex mais simples: corresponder diretamente uma string
pattern = r"hello"
text = "hello world"
result = re.search(pattern, text)
if result:
print("Encontrado!") # Encontrado!
print(result.group()) # hello
print(result.start()) # 0 (posição inicial)
print(result.end()) # 5 (posição final)
r (raw string). r"\n" é barra invertida + letra n, não uma nova linha. Regex usa barras invertidas extensivamente; sem r, você teria que escrever \\n, o que é doloroso.
2. Métodos Comuns
import re
text = "Meu email é alice@example.com, também bob@teste.com"
# search() — encontra a primeira correspondência
result = re.search(r"\w+@\w+\.\w+", text)
print(result.group()) # alice@example.com
# findall() — encontra todas as correspondências
emails = re.findall(r"\w+@\w+\.\w+", text)
print(emails) # ['alice@example.com', 'bob@teste.com']
# match() — corresponde a partir do início
print(re.match(r"Meu", text)) # Match (no início)
print(re.match(r"email", text)) # None (não no início)
# sub() — substituir
masked = re.sub(r"\w+@", "***@", text)
print(masked) # Meu email é ***@example.com, também ***@teste.com
3. Referência Rápida de Metacaracteres
| Metacaractere | Significado | Exemplo | Correspondências |
|---|---|---|---|
. |
Qualquer caractere (exceto nova linha) | h.t |
hat, hot, hit |
\d |
Dígito | \d{3} |
123, 456 |
\w |
Letra/dígito/sublinhado | \w+ |
hello, abc123 |
\s |
Espaço em branco | \s |
espaço, tab, nova linha |
* |
0 ou mais do anterior | ab*c |
ac, abc, abbc |
+ |
1 ou mais do anterior | ab+c |
abc, abbc (não ac) |
? |
0 ou 1 do anterior | colou?r |
color, colour |
{n} |
Exatamente n vezes | \d{4} |
2026, 1990 |
{n,m} |
n a m vezes | \d{2,4} |
23, 456, 2026 |
^ |
Início da string | ^Hello |
Hello... |
$ |
Fim da string | fim$ |
...fim |
[] |
Conjunto de caracteres | [aeiou] |
Qualquer vogal |
| ` | ` | OU | `gato |
▶ Exemplo: Validação de Telefone (Dificuldade ⭐⭐)
▶ ExperimenteSaída:
# Function defined successfully
4. Captura de Grupos
Use parênteses () para dividir o conteúdo correspondido em múltiplas partes:
import re
# Extrair nome de usuário e domínio de um email
email = "alice@example.com"
pattern = r"(\w+)@(\w+\.\w+)"
result = re.search(pattern, email)
if result:
print(f"Correspondência completa: {result.group(0)}") # alice@example.com
print(f"Usuário: {result.group(1)}") # alice
print(f"Domínio: {result.group(2)}") # example.com
# Extrair informações de um log
log = "2026-06-23 15:30:45 ERRO Timeout de conexão com banco de dados"
pattern = r"(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2}) (\w+) (.+)"
result = re.search(pattern, log)
print(f"Data: {result.group(1)}") # 2026-06-23
print(f"Hora: {result.group(2)}") # 15:30:45
print(f"Nível: {result.group(3)}") # ERRO
print(f"Mensagem: {result.group(4)}") # Timeout de conexão com banco de dados
▶ Exemplo: Analisador de URL (Dificuldade ⭐⭐⭐)
▶ ExperimenteSaída:
# Function defined successfully
▶ Exemplo: Substituição e Mascaramento de Texto (Dificuldade ⭐⭐)
▶ ExperimenteSaída:
Telefone mascarado: O telefone de Alice é 138****8000, email é alice@example.com, CPF 110101199001011234
Email mascarado: O telefone de Alice é 13800138000, email é al***@example.com, CPF 110101199001011234
CPF mascarado: O telefone de Alice é 13800138000, email é alice@example.com, CPF 1101**********1234
Resultado do template: Olá, Alice! Pedido PED2024001 foi enviado.
5. Matching Greedy vs Lazy
Por padrão, * e + são greedy — eles correspondem o máximo possível. Adicionar ? os torna lazy — eles correspondem o mínimo possível:
import re
text = "<h1>Título</h1><p>Parágrafo</p>"
# Modo greedy — corresponde o máximo possível
greedy = re.search(r"<.+>", text)
print(greedy.group()) # <h1>Título</h1><p>Parágrafo</p>
# Modo lazy — corresponde o mínimo possível (adicione ?)
lazy = re.search(r"<.+?>", text)
print(lazy.group()) # <h1>
.*? (lazy) vs .* (greedy): Ao trabalhar com conteúdo estruturado como HTML ou JSON, o modo lazy é mais comum. O modo greedy frequentemente "ultrapassa" para corresponder conteúdo que não deveria. Em caso de dúvida, comece com lazy.
6. Casos de Uso Comuns
- Validação de formulário: Valide formato de email, números de telefone, números de identidade.
- Extração de dados: Extraia padrões específicos de páginas web, logs e texto.
- Substituição de texto: Substitua em lote conteúdo que corresponda a um padrão (ex.: mascarar números de telefone).
- Realce de sintaxe: Editores usam regex para identificar palavras-chave e strings.
- Análise de log: Filtre e processe padrões específicos de arquivos de log massivos.
❓ Perguntas Frequentes
r em regex?r indica uma raw string. Em uma string normal, \n é uma nova linha; em uma raw string, \n é apenas barra invertida + letra n. Regex usa barras invertidas extensivamente (como \d, \w); sem r, você teria que escrever \\d, o que é muito doloroso.(.*)*) podem causar "catastrophic backtracking" — levando minutos para texto simples. Soluções: evite quantificadores aninhados, use modo lazy e use re.compile() para padrões usados com frequência.re.VERBOSE permite espaços e comentários em regex. ② Divida em vários padrões simples. ③ Use ferramentas online como regex101.com para depuração. Regex é o clássico "divertido de escrever, doloroso de ler" — não tente resolver tudo com um único regex.📖 Resumo
re.search()encontra a primeira correspondência;findall()encontra todas;sub()substitui- Metacaracteres:
\ddígito,\wcaractere de palavra,\sespaço em branco,.qualquer caractere - Quantificadores:
*qualquer,+pelo menos 1,?0 ou 1,{n}exatamente n - Grupos
()extraem partes;group(1)obtém o primeiro grupo - Greedy corresponde o máximo possível; adicione
?para lazy (o mínimo possível) - Sempre prefixe regex com
rpara evitar inferno de barras invertidas
📝 Exercícios
-
Básico (Dificuldade ⭐): Escreva uma função
is_valid_email(email)que usa regex para validar um endereço de email (contém@, não vazio em ambos os lados, tem sufixo de domínio). -
Intermediário (Dificuldade ⭐⭐): Escreva uma função
extract_numbers(text)que extrai todos os números (incluindo inteiros e decimais) de uma string e retorna sua soma. Por exemplo,"Preço é 19.99, frete 5, cupom -10"→ retorna 14.99. -
Desafio (Dificuldade ⭐⭐⭐): Escreva um "mecanismo de template simples." Dado o template
"Olá, {nome}! Seu pedido {pedido_id} foi enviado, chegando em {dias} dias."e um dicionário{"nome": "Alice", "pedido_id": "2024001", "dias": 3}, use regex para substituir todos os placeholders{variavel}por valores reais. Dica: Usere.sub()com uma função de callback.