W3docs

Grupos em Strings Python — Grupos de Captura com Regex

Aprenda como funcionam os grupos de captura em regex Python: group(), groups(), grupos nomeados, não-capturantes e referências retroativas.

Quando o módulo re do Python encontra uma correspondência dentro de uma string, ele retorna um objeto de correspondência. O objeto de correspondência é mais do que um simples resultado sim/não — ele lembra cada sub-padrão que você envolveu entre parênteses, chamado de grupo de captura. Os métodos .group() e .groups() são a forma de recuperar essas partes capturadas.

Este capítulo aborda tudo o que você precisa para usar grupos com confiança: grupos numerados, grupos nomeados, grupos não-capturantes, referências retroativas em substituições e erros comuns.

O que é um Grupo de Captura?

Um grupo de captura é uma parte de um padrão regex envolta em parênteses simples (...). Quando o padrão encontra uma correspondência, o Python salva o texto correspondido por cada par de parênteses separadamente, além de salvar toda a correspondência.

import re

m = re.search(r'(\d{4})-(\d{2})-(\d{2})', '2024-03-15')

print(m.group(0))  # 2024-03-15  — the whole match
print(m.group(1))  # 2024        — first group
print(m.group(2))  # 03          — second group
print(m.group(3))  # 15          — third group

Os grupos são numerados da esquerda para a direita, começando em 1, na ordem em que o parêntese de abertura aparece. group(0) (ou apenas group() sem argumento) sempre retorna toda a correspondência.

O Método .group()

.group(n) retorna o texto correspondido pelo n-ésimo grupo de captura. Você pode passar múltiplos índices de uma vez para obter uma tupla de resultados.

import re

m = re.search(r'(\w+)@(\w+)\.(\w+)', '[email protected]')

# Individual groups
print(m.group(1))       # alice
print(m.group(2))       # example
print(m.group(3))       # com

# Multiple at once
print(m.group(1, 3))    # ('alice', 'com')

Se um grupo existe no padrão mas não participou da correspondência (por exemplo, estava dentro de uma seção opcional), group(n) retorna None.

import re

# group(1) is optional — it may not match
m = re.search(r'(\d+)?-(\d+)', 'abc-456')
print(m.group(1))  # None  (the optional \d+ did not match)
print(m.group(2))  # 456

O Método .groups()

.groups() retorna uma tupla contendo o texto correspondido por cada grupo de captura, em ordem. É um atalho conveniente quando você quer todos os grupos de uma vez.

import re

m = re.search(r'(\d{4})-(\d{2})-(\d{2})', '2024-03-15')
print(m.groups())  # ('2024', '03', '15')

Fornecendo um Valor Padrão para Grupos Sem Correspondência

Se um grupo não participou da correspondência, ele aparece como None na tupla. Você pode fornecer um argumento default para substituir esses valores None por algo mais útil.

import re

m = re.search(r'(\d+)?-(\d+)', 'abc-456')
print(m.groups())              # (None, '456')
print(m.groups(default='0'))   # ('0', '456')

Grupos Nomeados com (?P<name>...)

Grupos numerados se tornam difíceis de rastrear em padrões complexos. Grupos nomeados permitem que você atribua um rótulo significativo a cada grupo usando a sintaxe (?P<name>...), e então recupere o valor pelo nome em vez da posição.

import re

pattern = r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})'
m = re.search(pattern, '2024-03-15')

print(m.group('year'))   # 2024
print(m.group('month'))  # 03
print(m.group('day'))    # 15

Grupos nomeados ainda têm um número, portanto você pode acessá-los de qualquer forma.

O Método .groupdict()

Quando você tem grupos nomeados, .groupdict() retorna um dicionário mapeando cada nome ao seu texto correspondido. Isso é útil quando você quer desempacotar uma correspondência em um objeto estruturado.

import re

m = re.search(
    r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})',
    '2024-03-15'
)
print(m.groupdict())
# {'year': '2024', 'month': '03', 'day': '15'}

Você pode então usar o resultado diretamente:

date_parts = m.groupdict()
print(f"{date_parts['day']}/{date_parts['month']}/{date_parts['year']}")
# 15/03/2024

Grupos Não-Capturantes com (?:...)

Às vezes você precisa agrupar parte de um padrão para aplicar um quantificador ou uma alternância, mas não quer que esse grupo apareça nos resultados da correspondência. Use (?:...) — um grupo não-capturante.

import re

# Without non-capturing group: both parts appear in groups()
m1 = re.search(r'(\d{4})-(\d{2})-(\d{2})', '2024-03-15')
print(m1.groups())  # ('2024', '03', '15')

# Year grouped but not captured — month and day are groups 1 and 2
m2 = re.search(r'(?:\d{4})-(\d{2})-(\d{2})', '2024-03-15')
print(m2.groups())  # ('03', '15')

Grupos não-capturantes são uma boa prática quando você não precisa de uma sub-correspondência específica — eles mantêm seus índices de grupo limpos e evitam desperdício de memória.

Grupos Aninhados

Grupos podem ser aninhados. A numeração é sempre baseada na posição do parêntese de abertura, contando da esquerda para a direita.

import re

# ((\d{4})-(\d{2}))-(\d{2})
# group 1 = the outer (year-month pair)
# group 2 = year
# group 3 = month
# group 4 = day
m = re.search(r'((\d{4})-(\d{2}))-(\d{2})', '2024-03-15')
print(m.group(1))   # 2024-03
print(m.group(2))   # 2024
print(m.group(3))   # 03
print(m.group(4))   # 15
print(m.groups())   # ('2024-03', '2024', '03', '15')

Grupos com re.findall()

Quando você usa re.findall() e o padrão contém exatamente um grupo de captura, ele retorna uma lista de strings — uma por correspondência.

Quando o padrão contém dois ou mais grupos de captura, ele retorna uma lista de tuplas.

import re

# One group → list of strings
emails = '[email protected], [email protected]'
usernames = re.findall(r'(\w+)@\w+\.\w+', emails)
print(usernames)  # ['alice', 'bob']

# Two groups → list of tuples
pairs = re.findall(r'(\w+)@(\w+)\.com', emails)
print(pairs)  # [('alice', 'gmail'), ('bob', 'yahoo')]

Grupos com re.finditer()

re.finditer() retorna um iterador de objetos de correspondência, então você pode acessar .group() e .groups() em cada um individualmente. Esta é a abordagem mais flexível quando você precisa de todos os detalhes da correspondência para cada ocorrência.

import re

text = '[email protected], [email protected]'
for m in re.finditer(r'(?P<user>\w+)@(?P<domain>\w+)\.com', text):
    print(m.group('user'), '->', m.group('domain'))
# alice -> gmail
# bob   -> yahoo

Referências Retroativas em re.sub()

Grupos de captura também habilitam referências retroativas em re.sub(). Na string de substituição, \1, \2, … referem-se ao texto capturado pelo grupo 1, grupo 2, e assim por diante. Grupos nomeados usam \g<name>.

import re

# Swap first and last name
result = re.sub(r'(\w+)\s(\w+)', r'\2 \1', 'John Smith')
print(result)  # Smith John

# Same using named groups
result2 = re.sub(
    r'(?P<first>\w+)\s(?P<last>\w+)',
    r'\g<last> \g<first>',
    'Jane Doe'
)
print(result2)  # Doe Jane

Posição de um Grupo: .start(), .end(), .span()

Objetos de correspondência expõem a posição de cada grupo, não apenas seu texto. Passe um número de grupo (ou nome) para .start(), .end() ou .span().

import re

m = re.search(r'(\d{4})-(\d{2})', '2024-03')
print(m.span(1))    # (0, 4)  — year occupies indices 0..3
print(m.start(2))   # 5       — month starts at index 5
print(m.end(2))     # 7       — month ends before index 7

Referência Rápida

MétodoRetornaNotas
m.group() ou m.group(0)String da correspondência completaSempre disponível
m.group(n)Texto correspondido pelo grupo nNone se o grupo não correspondeu
m.group(n, m, ...)Tupla de gruposMúltiplos índices em uma chamada
m.groups()Tupla de todos os gruposdefault= opcional para não correspondidos
m.groupdict()Dict de grupos nomeadosApenas grupos nomeados aparecem
m.start(n) / m.end(n)Índice de início / fim do grupo nPasse 0 para a correspondência completa
m.span(n)Tupla (start, end)Atalho para ambos

Erros Comuns

Usar .group() sem verificar None. re.search() retorna None quando não há correspondência, então chamar .group() diretamente no resultado lança AttributeError. Sempre proteja a chamada:

import re

m = re.search(r'(\d+)', 'no digits here')
if m:
    print(m.group(1))
else:
    print('no match')
# no digits here

Confundir .group() com .groups(). .group(1) retorna uma string; .groups() sempre retorna uma tupla. Misturá-los causa erros de tipo sutis.

Esquecer que re.findall() muda de forma com grupos. Sem grupos, retorna uma lista plana de strings; com grupos, retorna uma lista de tuplas. Adicionar ou remover um grupo de captura pode quebrar silenciosamente o código que processa o resultado.

Quando Usar Cada Abordagem

  • Use grupos numerados para padrões simples e curtos com poucos grupos.
  • Use grupos nomeados quando os padrões são complexos, ou quando você usará o resultado em várias linhas de código — os nomes funcionam como autodocumentação.
  • Use grupos não-capturantes (?:...) sempre que precisar de agrupamento apenas para aplicar um quantificador ou alternância, não para extrair um valor.
  • Use .groups() para desempacotar todas as capturas de uma vez em uma tupla.
  • Use .groupdict() quando todos os grupos são nomeados e você quer um dicionário.

Para uma visão geral mais ampla do módulo re e sua sintaxe de padrões, consulte o capítulo Python RegEx. Para operações com strings que não requerem regex, consulte Modify Strings e Python String Methods.

Prática

Prática
In Python, which functions or methods can be used to define a group within strings?
In Python, which functions or methods can be used to define a group within strings?
Was this page helpful?