Expressões Regulares em Python: Guia Prático para Automação de Scripts

Expressões regulares (Regex) funcionam como uma "faca suíça" para o processamento de texto. Emmbora sua sintaxe possa parecer intimidadora à primeira vista, dominar essa ferramenta permite que desenvolvedores Python criem scripts de automação robustos para extrair informações, validar dados e manipular strings com eficiência.

Fundamentos do Módulo re

No Python, a biblioteca padrão re é a porta de entrada para trabalhar com padrões de busca. Diferente dos métodos de string convencionais, o Regex permite buscas baseadas em regras complexas.

import re

# Exemplo básico de busca
conteudo = "Entre em contato através do email suporte@empresa.com.br hoje mesmo."
padrao_email = r'[\w.-]+@[\w.-]+\.[a-zA-Z]{2,}'

busca = re.search(padrao_email, conteudo)
if busca:
    print(f"Email detectado: {busca.group()}")

# Comparativo entre métodos principais
amostra = "ID: 450, Valor: R$ 1250.50, Data: 2023-10-25"

# search: Localiza a primeira ocorrência
primeiro_numero = re.search(r'\d+', amostra)
print(f"Primeiro número: {primeiro_numero.group()}") # 450

# findall: Retorna uma lista com todas as ocorrências
todos_numeros = re.findall(r'\d+', amostra)
print(f"Lista completa: {todos_numeros}") # ['450', '1250', '50', '2023', '10', '25']

# finditer: Ideal para processar grandes volumes (retorna iterador)
for item in re.finditer(r'\d{4}-\d{2}-\d{2}', amostra):
    print(f"Data encontrada na posição {item.span()}: {item.group()}")

Classes de Caracteres e Atalhos

Para construir padrões eficientes, utilizamos metacaracteres que representam grupos de caracteres:

  • \d: Qualquer dígito numérico (0-9).
  • \w: Caracteres alfanuméricos e sublinhado (_).
  • \s: Espaços em branco, tabs e quebras de linha.
  • .: Qualquer caractere, exceto nova linha.
  • [A-Z]: Qualquer letra maiúscula.
# Exemplo de captura com grupos
registro = "ACESSO_WEB - Usuario: admin123 - Prioridade: ALTA"
padrao_usuario = r"Usuario: (\w+) - Prioridade: (\w+)"

match = re.search(padrao_usuario, registro)
if match:
    # O group(0) é a correspondência completa, 1 e 2 são os grupos ()
    print(f"Username: {match.group(1)}")
    print(f"Nível: {match.group(2)}")

Aplicações Reais em Scripts de Automação

1. Análise de Logs do Sistema

Scripts de monitoramento frequentemente precisam filtrar arquivos de log para identificar falhas críticas.

import re
from collections import Counter

logs_servidor = """
[2023-11-01 08:00:01] INFO: Sistema iniciado
[2023-11-01 08:05:22] ERROR: Falha na conexão com banco (Timeout)
[2023-11-01 08:06:45] WARNING: Latência alta detectada
[2023-11-01 08:10:12] ERROR: Autenticação negada para user 'guest'
"""

def processar_logs(texto):
    # Padrão: [data] NÍVEL: Mensagem
    regex_log = r'\[(?P<data>.*?)\] (?P<nivel>[A-Z]+): (?P<msg>.*)'
    
    erros = []
    contagem_niveis = Counter()
    
    for linha in texto.strip().split('\n'):
        m = re.match(regex_log, linha)
        if m:
            nivel = m.group('nivel')
            contagem_niveis[nivel] += 1
            if nivel == 'ERROR':
                erros.append(m.group('msg'))
                
    return contagem_niveis, erros

resumo, lista_erros = processar_logs(logs_servidor)
print(f"Resumo: {dict(resumo)}")
print(f"Mensagens de erro: {lista_erros}")

2. Renomeação em Massa de Arquivos

Utilizar Regex para limpar nomes de aqruivos recebidos de fontes externas ou backups.

import re
import os

def normalizar_arquivos(diretorio, padrao_busca, novo_formato):
    # Exemplo: Transformar "DOC_2023_RELATORIO.pdf" em "RELATORIO_2023.pdf"
    for nome_antigo in os.listdir(diretorio):
        if re.search(padrao_busca, nome_antigo):
            nome_novo = re.sub(padrao_busca, novo_formato, nome_antigo)
            print(f"Renomeando: {nome_antigo} -> {nome_novo}")
            # os.rename(os.path.join(diretorio, nome_antigo), os.path.join(diretorio, nome_novo))

# Uso: Captura o ano e o nome, inverte a ordem
# padrao = r"DOC_(\d{4})_(.*)\.pdf"
# normalizar_arquivos("./docs", padrao, r"\2_\1.pdf")

3. Validação e Higienização de Dados

Garantir que os dados inseridos em um sistema seguem o formato esperado.

def limpar_telefone(tel_bruto):
    # Remove tudo que não for dígito
    apenas_numeros = re.sub(r'\D', '', tel_bruto)
    
    # Valida formato brasileiro (ex: 11988887777 ou 1133334444)
    if re.match(r'^\d{10,11}$', apenas_numeros):
        return apenas_numeros
    return None

telefones = ["(11) 98888-7777", "11 3333 4444", "abc-1234"]
validados = [limpar_telefone(t) for t in telefones]
print(f"Telefones limpos: {validados}")

Recursos Avançados

Lookarounds (Âncoras de Contexto)

Permite validar se um padrão é precedido ou seguido por outro, sem incluir esses caracteres no resultado da captura.

# Lookahead Positivo (?=...) - Busca valor seguido de ' USD'
precos = "Produto A: 100 USD, Produto B: 250 EUR"
valores_dolar = re.findall(r'\d+(?= USD)', precos)
print(valores_dolar) # ['100']

# Lookbehind Positivo (?<=...) - Busca dígitos precedidos por 'ID-'
ids_texto = "ID-550, ID-920, REF-100"
numeros_id = re.findall(r'(?<=ID-)\d+', ids_texto)
print(numeros_id) # ['550', '920']

Compilação de Padrões

Se uma expressão será executada milhares de vezes em um loop, compilá-la aumenta a performence.

# Pré-compilação para reuso
REG_CPF = re.compile(r'\d{3}\.\d{3}\.\d{3}-\d{2}')

lista_cpfs = ["123.456.789-00", "000.111.222-33"]
for cpf in lista_cpfs:
    if REG_CPF.match(cpf):
        print(f"{cpf} é válido.")

Resumo de Sintaxe

Símbolo Descrição Exemplo
^ / $ Início / Fim da string ^Log
+ / * 1 ou mais / 0 ou mais ocorrências \d+
? 0 ou 1 ocorrência (ou torna o quantificador não-guloso) https?
{n,m} De n a m repetições \d{2,4}
| Operador OU (jpg|png|gif)
[] Conjunto de caracteres específicos [aeiou]

Embora poderosas, as expressões regulares devem ser usadas com cautela. Para manipulações simples como trocar extensões de arquivos ou converter cases, os métodos nativos .split(), .replace() e .startswith() costumam ser mais legíveis e performáticos.

Tags: Python Regex Automação scripting TextProcessing

Publicado em 8-4 20:04