Expressões regulares (regex) são padrões de busca em texto. Com elas você valida formatos (CPF, e-mail, telefone), extrai informações específicas de strings não estruturadas e realiza substituições complexas — operações que funções de string simples não conseguem fazer.

O módulo re

import re

Funções principais: re.search(), re.match(), re.findall(), re.sub(), re.compile().

Padrões básicos

Validando formatos

# Validar e-mail:
def valida_email(email):
    padrao = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
    return bool(re.match(padrao, email))

print(valida_email("ana@empresa.com.br"))  # True
print(valida_email("email_invalido"))      # False

# Validar telefone brasileiro (com ou sem DDD):
def valida_telefone(tel):
    # Remove formatação:
    tel_limpo = re.sub(r'[\s()\-.]', '', tel)
    padrao = r'^\+?55?\d{10,11}$'
    return bool(re.match(padrao, tel_limpo))

# Verificar se string contém apenas números:
def so_numeros(texto):
    return bool(re.match(r'^\d+$', texto))

Extraindo padrões de texto

texto = "Pedido #1234 em 15/03/2026 no valor de R$ 1.890,00"

# Extrair o número do pedido:
match = re.search(r'#(\d+)', texto)
if match:
    print(match.group(1))   # 1234

# Extrair todas as datas no formato DD/MM/AAAA:
datas = re.findall(r'\d{2}/\d{2}/\d{4}', texto)
print(datas)   # ['15/03/2026']

# Extrair o valor:
valor = re.search(r'R\$\s*([\d.]+,\d{2})', texto)
if valor:
    print(valor.group(1))   # 1.890,00

Substituições com re.sub()

# Remover formatação de CPF: "123.456.789-01" -> "12345678901"
cpf = "123.456.789-01"
cpf_limpo = re.sub(r'[.\-]', '', cpf)   # 12345678901

# Remover HTML tags de um texto:
html = "Vendas cresceram 15% no trimestre"
texto_limpo = re.sub(r'<[^>]+>', '', html)
# "Vendas cresceram 15% no trimestre"

# Normalizar espaços múltiplos:
texto = "Ana  Silva   Vendas"
normalizado = re.sub(r'\s+', ' ', texto).strip()
# "Ana Silva Vendas"

Aplicando regex em coluna Pandas

import pandas as pd

df = pd.DataFrame({"telefone": ["(11) 98765-4321", "11987654321", "011-9876-5432"]})

# Extrair apenas os dígitos:
df["tel_numeros"] = df["telefone"].str.replace(r'\D', '', regex=True)

# Filtrar linhas que contêm um padrão:
df_sp = df[df["telefone"].str.contains(r'^\(11\)', regex=True)]

Perguntas frequentes

Quando usar raw strings (r"...") em regex?

Sempre. Em strings normais, \d pode ser interpretado pelo Python como escape de 'd'. Com r"\d", o Python passa a string literalmente para o motor de regex sem processar os backslashes.

re.compile() vs. re.search() direto?

Use re.compile(padrao) quando você vai usar o mesmo padrão muitas vezes em um loop — o padrão compilado é mais rápido. Para uso único, re.search() direto é suficiente.