W3docs

Python RegEx

Aprenda expressões regulares em Python: sintaxe, sequências especiais, grupos, lookaheads, flags e funções do módulo re com exemplos claros.

Expressões regulares (regex) permitem pesquisar, extrair e substituir texto com base em padrões flexíveis em vez de strings exatas. O módulo re integrado do Python fornece tudo o que você precisa. Este capítulo cobre o conjunto completo de ferramentas de regex: sintaxe, sequências especiais, quantificadores, grupos, lookahead/lookbehind, flags e todas as funções essenciais do re — com exemplos corretos e executáveis ao longo do texto.

Por que Usar Expressões Regulares?

Os métodos de string comuns (str.find(), str.replace(), str.split()) funcionam bem para textos fixos. As expressões regulares se destacam quando o padrão varia:

  • Validar se uma string parece um endereço de e-mail ou número de telefone.
  • Extrair todas as datas de um documento, independentemente do formato exato.
  • Remover tags HTML de uma string.
  • Substituir múltiplas sequências de espaços em branco diferentes por um único espaço.

Quando a tarefa envolve descrever uma forma em vez de um valor fixo, use re.

Raw Strings

Os padrões de regex são quase sempre escritos como raw strings (r'...'). As raw strings tratam barras invertidas como caracteres literais, o que importa porque o regex usa muitas sequências com barra invertida (\d, \w, \s, \b). Sem o prefixo r, você precisaria de barras invertidas duplas em todo lugar:

import re

# Both patterns are identical — raw string is easier to read
re.findall(r'\d+', 'abc 123')   # raw:    r'\d+'
re.findall('\\d+', 'abc 123')   # normal: '\\d+'

Use raw strings para todo padrão de regex — é a convenção universal.

Sintaxe Básica: Metacaracteres

Metacaracteres são caracteres com significado especial dentro de um padrão. Caracteres literais correspondem exatamente a si mesmos.

MetacaractereSignificado
.Qualquer caractere exceto nova linha
^Início da string (ou de linha no modo MULTILINE)
$Fim da string (ou de linha no modo MULTILINE)
*Zero ou mais do elemento anterior
+Um ou mais do elemento anterior
?Zero ou um do elemento anterior
{n}Exatamente n repetições
{n,m}Entre n e m repetições
[...]Classe de caractere — qualquer caractere listado dentro
[^...]Classe negada — qualquer caractere não listado
|Alternância — a expressão da esquerda ou da direita
()Grupo de captura
\Escapar um metacaractere ou iniciar uma sequência especial

Para corresponder a um metacaractere literal como . ou *, escape-o com barra invertida: \. corresponde a um ponto real.

Sequências Especiais

Sequências especiais são classes de caracteres abreviadas que aparecem frequentemente em padrões do mundo real.

SequênciaCorresponde a
\dQualquer dígito — equivalente a [0-9]
\DQualquer não-dígito
\wCaractere de palavra: letras, dígitos, sublinhado
\WCaractere que não é de palavra
\sEspaço em branco: espaço, tabulação, nova linha
\SNão-espaço em branco
\bLimite de palavra (largura zero)
\BNão-limite
import re

print(re.findall(r'\d+', 'I have 3 cats and 12 dogs'))
# ['3', '12']

print(re.findall(r'\w+', 'hello_world 123'))
# ['hello_world', '123']

print(re.findall(r'\bPython\b', 'Python Pythonista Python3'))
# ['Python']  — word boundary prevents partial matches

\b é particularmente útil: corresponde à posição entre um caractere de palavra e um não-caractere de palavra, portanto \bPython\b corresponde à palavra isolada "Python", mas não a "Pythonista" ou "Python3".

Quantificadores

Quantificadores controlam quantas vezes o elemento anterior deve corresponder.

import re

print(re.findall(r'a*', 'baaa'))   # ['', 'aaa', '']
print(re.findall(r'a+', 'baaa'))   # ['aaa']
print(re.findall(r'a?', 'baaa'))   # ['', 'a', 'a', 'a', '']
print(re.findall(r'a{3}', 'baaa')) # ['aaa']

Correspondência Gananciosa vs. Lazy

Por padrão, os quantificadores são gananciosos — eles correspondem ao máximo de texto possível. Adicione ? após o quantificador para torná-lo lazy (corresponder o mínimo possível).

import re

html = '<b>bold</b> and <i>italic</i>'

print(re.findall(r'<.*>', html))
# ['<b>bold</b> and <i>italic</i>']  — greedy: matches from first < to last >

print(re.findall(r'<.*?>', html))
# ['<b>', '</b>', '<i>', '</i>']  — lazy: matches each individual tag

Quantificadores lazy são essenciais ao analisar texto estruturado como HTML ou fragmentos JSON.

Classes de Caracteres

Uma classe de caractere [...] corresponde a qualquer caractere do conjunto listado. Use - para intervalos e ^ no início para negar a classe.

import re

print(re.findall(r'[aeiou]', 'hello world'))
# ['e', 'o', 'o']

print(re.findall(r'[0-9]', 'a1b2c3'))
# ['1', '2', '3']

print(re.findall(r'[^aeiou\s]+', 'hello world'))
# ['h', 'll', 'w', 'rld']  — consonants only (not vowels, not spaces)

Intervalos comuns prontos para uso: [a-z] letras minúsculas, [A-Z] maiúsculas, [0-9] dígitos, [a-zA-Z0-9] alfanumérico.

Âncoras

Âncoras não consomem caracteres — elas afirmam uma posição na string.

import re

print(re.findall(r'^Python', 'Python is great'))
# ['Python']  — matches only if 'Python' is at the start

print(re.findall(r'great$', 'Python is great'))
# ['great']  — matches only if 'great' is at the end

print(re.findall(r'^Python', 'Learn Python'))
# []  — 'Python' is not at the start of this string

Consulte a flag re.MULTILINE mais adiante neste capítulo para aplicar ^ e $ por linha em vez de por string.

Alternância

O pipe | funciona como um OR lógico entre duas expressões.

import re

print(re.findall(r'cat|dog', 'I have a cat and a dog'))
# ['cat', 'dog']

print(re.findall(r'colou?r|colour', 'color and colour'))
# ['color', 'colour']

Grupos de Captura

Parênteses () criam um grupo de captura. Os grupos permitem extrair partes de uma correspondência. re.search() retorna um objeto de correspondência; chame .group(n) ou .groups() nele.

import re

match = re.search(r'(\d{4})-(\d{2})-(\d{2})', '2023-10-05')
if match:
    print(match.group(0))   # '2023-10-05'  — entire match
    print(match.group(1))   # '2023'
    print(match.groups())   # ('2023', '10', '05')

Grupos Nomeados

Nomeie um grupo com (?P<name>...) para acessá-lo pelo nome em vez da posição. Isso torna os padrões muito mais fáceis de manter.

import re

match = re.search(
    r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})',
    '2023-10-05'
)
if match:
    print(match.group('year'))   # '2023'
    print(match.groupdict())     # {'year': '2023', 'month': '10', 'day': '05'}

Grupos Não-Capturadores

Use (?:...) quando precisar agrupar, mas não precisar capturar o valor.

import re

print(re.findall(r'(?:Mr|Mrs|Ms)\.? \w+', 'Mr. Smith and Mrs. Jones'))
# ['Mr. Smith', 'Mrs. Jones']

Lookahead e Lookbehind

Lookahead ((?=...)) e lookbehind ((?<=...)) afirmam que algo segue ou precede a correspondência, sem incluí-lo no resultado. Eles têm largura zero: não consomem caracteres.

import re

# Positive lookahead — find numbers followed by 'dollars'
print(re.findall(r'\d+(?= dollars)', '100 dollars and 200 euros'))
# ['100']

# Negative lookahead — find numbers NOT followed by 'dollars'
print(re.findall(r'\b\d+\b(?! dollars)', '100 dollars and 200 euros'))
# ['200']

# Positive lookbehind — extract domain from email addresses
emails = 'Contact [email protected] or [email protected]'
print(re.findall(r'(?<=@)\w+\.\w+', emails))
# ['example.com', 'test.org']

Os padrões lookbehind devem ter largura fixa em Python — não é possível usar * ou + dentro deles.

O Módulo re: Funções Principais

re.search() — Encontrar a Primeira Correspondência

Retorna um objeto de correspondência para o primeiro local onde o padrão corresponde, ou None se não houver correspondência.

import re

text = 'apple banana apple'
match = re.search(r'banana', text)
if match:
    print(match.group())   # 'banana'
    print(match.span())    # (6, 12)

re.match() — Corresponder Apenas no Início

Como re.search(), mas o padrão deve corresponder no início da string.

import re

print(bool(re.match(r'\d+', 'abc123')))   # False — no digit at start
print(bool(re.search(r'\d+', 'abc123')))  # True  — digit found anywhere

Use re.search() quando quiser encontrar um padrão em qualquer lugar; use re.match() quando o padrão deva aparecer no início.

re.fullmatch() — Corresponder a String Inteira

O padrão deve corresponder à string inteira do início ao fim.

import re

print(bool(re.fullmatch(r'\d{5}', '12345')))   # True  — exactly 5 digits
print(bool(re.fullmatch(r'\d{5}', '123456')))  # False — too long
print(bool(re.fullmatch(r'\d{5}', '1234X')))   # False — non-digit present

re.fullmatch() é ideal para validação de entrada (CEPs, números de telefone, etc.).

re.findall() — Todas as Correspondências Não Sobrepostas

Retorna uma lista de todas as correspondências. Se o padrão tiver grupos, retorna uma lista de tuplas.

import re

print(re.findall(r'\d+', 'abc 123 def 456'))
# ['123', '456']

# With a group — returns list of group values
print(re.findall(r'(\w+)@(\w+\.\w+)', '[email protected] [email protected]'))
# [('alice', 'example.com'), ('bob', 'test.org')]

re.finditer() — Iterador de Objetos de Correspondência

Como re.findall(), mas produz objetos de correspondência um de cada vez. Útil para textos grandes ou quando você precisa de informações de posição.

import re

for m in re.finditer(r'\d+', 'abc 123 def 456'):
    print(m.group(), m.start(), m.end())
# 123 4 7
# 456 12 15

re.sub() — Substituir Correspondências

Substitui cada ocorrência do padrão por uma string de substituição ou pelo valor de retorno de uma função.

import re

text = 'apple banana apple'
print(re.sub(r'apple', 'orange', text))
# 'orange banana orange'

# Limit replacements
print(re.sub(r'apple', 'orange', text, count=1))
# 'orange banana apple'

# Backreferences in replacement — reformat a date
print(re.sub(r'(\d{4})-(\d{2})-(\d{2})', r'\3/\2/\1', '2023-10-05'))
# '05/10/2023'

re.split() — Dividir por um Padrão

Divide a string em cada ocorrência do padrão.

import re

print(re.split(r',\s*', 'apple, banana, cherry, date'))
# ['apple', 'banana', 'cherry', 'date']

# Limit the number of splits
print(re.split(r',\s*', 'apple, banana, cherry, date', maxsplit=2))
# ['apple', 'banana', 'cherry, date']

Compilando Padrões com re.compile()

Quando você usa o mesmo padrão muitas vezes, compile-o uma vez com re.compile() para melhorar o desempenho. O objeto de padrão resultante tem todos os mesmos métodos (findall, search, sub, etc.).

import re

# Compile once
digit_pattern = re.compile(r'\d+')

# Reuse many times
print(digit_pattern.findall('abc 123 def 456'))   # ['123', '456']
print(digit_pattern.sub('NUM', 'abc 123 def 456')) # 'abc NUM def NUM'
print(digit_pattern.search('xyz 99'))              # <re.Match object ...>

A compilação é especialmente valiosa dentro de laços ou funções chamadas com frequência.

Flags

As flags modificam o comportamento da correspondência. Passe-as como último argumento para qualquer função re, ou inclua-as ao chamar re.compile(). Múltiplas flags podem ser combinadas com |.

FlagForma curtaEfeito
re.IGNORECASEre.ICorrespondência sem distinção entre maiúsculas e minúsculas
re.MULTILINEre.M^ e $ correspondem ao início/fim de cada linha
re.DOTALLre.S. também corresponde a novas linhas
re.VERBOSEre.XPermite espaços em branco e comentários dentro do padrão
import re

# IGNORECASE
print(re.findall(r'hello', 'Hello HELLO hello', re.IGNORECASE))
# ['Hello', 'HELLO', 'hello']

# MULTILINE — ^ matches the start of each line
text = 'first line\nsecond line\nthird line'
print(re.findall(r'^\w+', text, re.MULTILINE))
# ['first', 'second', 'third']

# DOTALL — . matches newline characters
print(re.findall(r'<.*?>', '<div>\n<p>text</p>\n</div>', re.DOTALL))
# ['<div>', '<p>', '</p>', '</div>']

# VERBOSE — write readable patterns with comments
date_pattern = re.compile(r'''
    (?P<year>\d{4})   # four-digit year
    -
    (?P<month>\d{2})  # two-digit month
    -
    (?P<day>\d{2})    # two-digit day
''', re.VERBOSE)
print(date_pattern.search('2023-10-05').groupdict())
# {'year': '2023', 'month': '10', 'day': '05'}

Escapando Entrada do Usuário com re.escape()

Se você construir um padrão a partir de texto fornecido pelo usuário, sempre o escape primeiro para evitar interpretações não intencionais de metacaracteres.

import re

user_input = 'hello.world'
# Without escaping, '.' matches any character
# With escaping, '\.' matches a literal dot
safe_pattern = re.escape(user_input)
print(safe_pattern)                                    # 'hello\\.world'
print(bool(re.search(safe_pattern, 'say hello.world')))  # True
print(bool(re.search(safe_pattern, 'say helloXworld')))  # False

Exemplos Práticos

Validar um Endereço de E-mail

import re

def is_valid_email(email):
    pattern = r'^[\w.+-]+@[\w-]+\.[a-zA-Z]{2,}$'
    return bool(re.fullmatch(pattern, email))

print(is_valid_email('[email protected]'))   # True
print(is_valid_email('bad-email@'))         # False

Extrair Todas as URLs do Texto

import re

text = 'Visit https://www.example.com or http://test.org for details.'
urls = re.findall(r'https?://[\w./-]+', text)
print(urls)
# ['https://www.example.com', 'http://test.org']

Remover Espaços em Branco Extras

import re

messy = '  hello    world   Python  '
clean = re.sub(r'\s+', ' ', messy).strip()
print(clean)  # 'hello world Python'

Analisar uma Linha de Log

import re

log = '2023-10-05 14:32:11 ERROR Failed to connect to database'
pattern = re.compile(
    r'(?P<date>\d{4}-\d{2}-\d{2}) '
    r'(?P<time>\d{2}:\d{2}:\d{2}) '
    r'(?P<level>\w+) '
    r'(?P<message>.+)'
)
m = pattern.match(log)
if m:
    print(m.group('level'))    # 'ERROR'
    print(m.group('message'))  # 'Failed to connect to database'

Armadilhas Comuns

re.match() vs re.search()re.match() verifica apenas o início da string. Novos usuários frequentemente esperam que ele pesquise em qualquer lugar e ficam confusos quando retorna None.

Esquecer raw strings'\d' em uma string Python normal é apenas 'd' com um escape não reconhecido (ou um SyntaxWarning no Python 3.12+). Sempre escreva r'\d'.

Correspondências gananciosas consumindo demais — Se um padrão .* capturar mais do que você pretendia, mude para .*? (lazy).

Caracteres especiais em strings de substituição — Em re.sub(), sequências com barra invertida como \1 na substituição referem-se a grupos capturados. Para incluir uma barra invertida literal na substituição, escreva \\.

re.findall() com grupos — Quando seu padrão contém grupos, re.findall() retorna os grupos, não a correspondência completa. Use um grupo não-capturador (?:...) se quiser a correspondência completa.

Referência Rápida

TarefaFunção
Encontrar primeira correspondênciare.search(pattern, text)
Encontrar todas as correspondênciasre.findall(pattern, text)
Iterar correspondênciasre.finditer(pattern, text)
Corresponder no iníciore.match(pattern, text)
Corresponder string inteirare.fullmatch(pattern, text)
Substituirre.sub(pattern, repl, text)
Dividirre.split(pattern, text)
Compilar para reutilizaçãore.compile(pattern)
Escapar entrada do usuáriore.escape(text)

Capítulos Relacionados

  • Python Strings — métodos de string que complementam o regex para tarefas de texto mais simples.
  • Modify Strings — métodos integrados como replace() e split() que dispensam o regex quando os padrões são fixos.
  • Python File Handling — leitura de arquivos linha por linha para aplicar regex em escala.
  • Python Try/Except — tratamento de erros que surgem quando padrões de regex são compilados a partir de entrada do usuário.
  • Python Functions — encapsulamento da lógica de regex em funções reutilizáveis.

Prática

Prática
What does the 're' module in Python provide?
What does the 're' module in Python provide?
Was this page helpful?