Expressões Regulares

Expressões Regulares

Uma expressão regular (abreviada como regex [...]) é uma sequência de caracteres que especifica um padrão de busca em texto. [...] usada por algoritmos de busca de strings para operações de "localizar" ou "localizar e substituir" em strings, ou para validação de entrada.

  1. Importe o módulo regex com import re.
  2. Crie um objeto Regex com a função re.compile(). (Lembre-se de usar uma string bruta/raw string.)
  3. Passe a string que você deseja pesquisar para o método search() do objeto Regex. Isso retorna um objeto Match.
  4. Chame o método group() do objeto Match para retornar uma string do texto realmente correspondido.

Todas as funções regex em Python estão no módulo re:

# Importa o módulo re para operações de expressão regular
import re

Símbolos Regex

SímboloCorresponde a
?zero ou uma ocorrência do grupo precedente.
*zero ou mais ocorrências do grupo precedente.
+uma ou mais ocorrências do grupo precedente.
{n}exatamente n ocorrências do grupo precedente.
{n,}n ou mais ocorrências do grupo precedente.
{,m}0 a m ocorrências do grupo precedente.
{n,m}no mínimo n e no máximo m ocorrências do p precedente.
{n,m}? ou *? ou +?executa uma correspondência não-gulosa (non-greedy) do p precedente.
^spamsignifica que a string deve começar com spam.
spam$significa que a string deve terminar com spam.
.qualquer caractere, exceto caracteres de nova linha.
\d, \w, e \sum dígito, palavra, ou caractere de espaço, respectivamente.
\D, \W, e \Squalquer coisa exceto um dígito, palavra, ou espaço, respectivamente.
[abc]qualquer caractere entre os colchetes (como a, b, ).
[^abc]qualquer caractere que não esteja entre os colchetes.

Objetos de correspondência Regex

# re.compile(): cria o objeto de padrão regex (use string bruta r'' para evitar escape)
phone_num_regex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')  # Padrão: 3 dígitos-3 dígitos-4 dígitos

mo = phone_num_regex.search('My number is 415-555-4242.')  # Procura pelo padrão

print(f'Phone number found: {mo.group()}')  # group() retorna o texto correspondido
Phone number found: 415-555-4242

Agrupamento com parênteses

# Parênteses criam grupos: group(1) retorna o primeiro grupo, group(2) retorna o segundo
phone_num_regex = re.compile(r'(\d\d\d)-(\d\d\d-\d\d\d\d)')  # Dois grupos entre parênteses
mo = phone_num_regex.search('My number is 415-555-4242.')

mo.group(1)  # Retorna o primeiro grupo: '415'
'415'
mo.group(2)
'555-4242'
mo.group(0)
'415-555-4242'
mo.group()
'415-555-4242'
Quiz

Faça login para responder este quiz e acompanhar seu progresso de aprendizagem

O que group() retorna quando chamado em um objeto de correspondência?
A. O texto correspondido inteiro
B. Apenas o primeiro grupo
C. Todos os grupos como uma lista
D. O índice da correspondência

Para recuperar todos os grupos de uma vez, use o método groups():

# groups(): retorna uma tupla de todos os grupos
mo.groups()  # Retorna ('415', '555-4242')
('415', '555-4242')
area_code, main_number = mo.groups()

print(area_code)
415
print(main_number)
555-4242

Múltiplos grupos com Pipe

Você pode usar o caractere | onde quiser corresponder a uma de muitas expressões.

hero_regex = re.compile (r'Batman|Tina Fey')

mo1 = hero_regex.search('Batman and Tina Fey.')
mo1.group()
'Batman'
mo2 = hero_regex.search('Tina Fey and Batman.')
mo2.group()
'Tina Fey'

Você também pode usar o pipe para corresponder a um de vários padrões como parte do seu regex:

bat_regex = re.compile(r'Bat(man|mobile|copter|bat)')
mo = bat_regex.search('Batmobile lost a wheel')

mo.group()
'Batmobile'
mo.group(1)
'mobile'

Correspondência opcional com o Ponto de Interrogação

O caractere ? sinaliza o grupo que o precede como uma parte opcional do padrão.

bat_regex = re.compile(r'Bat(wo)?man')

mo1 = bat_regex.search('The Adventures of Batman')
mo1.group()
'Batman'
mo2 = bat_regex.search('The Adventures of Batwoman')
mo2.group()
'Batwoman'

Correspondência de zero ou mais com o Asterisco

O * (asterisco) significa “corresponder zero ou mais”. O grupo que precede o asterisco pode ocorrer qualquer número de vezes no texto.

bat_regex = re.compile(r'Bat(wo)*man')
mo1 = bat_regex.search('The Adventures of Batman')
mo1.group()
'Batman'
mo2 = bat_regex.search('The Adventures of Batwoman')
mo2.group()
'Batwoman'
mo3 = bat_regex.search('The Adventures of Batwowowowoman')
mo3.group()
'Batwowowowoman'

Correspondência de um ou mais com o Mais

O + (ou mais) significa corresponder um ou mais. O grupo que precede um mais deve aparecer pelo menos uma vez:

bat_regex = re.compile(r'Bat(wo)+man')

mo1 = bat_regex.search('The Adventures of Batwoman')
mo1.group()
'Batwoman'
mo2 = bat_regex.search('The Adventures of Batwowowowoman')
mo2.group()
'Batwowowowoman'
mo3 = bat_regex.search('The Adventures of Batman')
mo3 is None
True

Correspondência de repetições específicas com Chaves

Se você tem um grupo que deseja repetir um número específico de vezes, siga o grupo no seu regex com um número entre chaves:

ha_regex = re.compile(r'(Ha){3}')

mo1 = ha_regex.search('HaHaHa')
mo1.group()
'HaHaHa'
mo2 = ha_regex.search('Ha')
mo2 is None
True

Em vez de um número, você pode especificar um intervalo com um mínimo e um máximo entre as chaves. Por exemplo, o regex (Ha){3,5} corresponderá a ‘HaHaHa’, ‘HaHaHaHa’ e ‘HaHaHaHaHa’.

ha_regex = re.compile(r'(Ha){2,3}')
mo1 = ha_regex.search('HaHaHaHa')
mo1.group()
'HaHaHa'

Correspondência gulosa (Greedy) e não-gulosa (Non-greedy)

As expressões regulares do Python são gulosas (greedy) por padrão: em situações ambíguas, elas corresponderão à string mais longa possível. A versão não-gulosa das chaves, que corresponde à string mais curta possível, tem a chave de fechamento seguida por um ponto de interrogação.

greedy_ha_regex = re.compile(r'(Ha){3,5}')

mo1 = greedy_ha_regex.search('HaHaHaHaHa')
mo1.group()
'HaHaHaHaHa'
non_greedy_ha_regex = re.compile(r'(Ha){3,5}?')
mo2 = non_greedy_ha_regex.search('HaHaHaHaHa')
mo2.group()
'HaHaHa'
Quiz

Faça login para responder este quiz e acompanhar seu progresso de aprendizagem

O que torna um padrão regex não-guloso (non-greedy)?
A. Usar _ em vez de +
B. Adicionar um ? após o quantificador (ex: _?, +?, {3,5}?)
C. Usar parênteses
D. Usar colchetes

O método findall()

O método findall() retornará as strings de cada correspondência na string pesquisada.

phone_num_regex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d') # não tem grupos

phone_num_regex.findall('Cell: 415-555-9999 Work: 212-555-0000')
['415-555-9999', '212-555-0000']

Criando suas próprias classes de caracteres

Você pode definir sua própria classe de caracteres usando colchetes. Por exemplo, a classe de caracteres [aeiouAEIOU] corresponderá a qualquer vogal, minúscula ou maiúscula.

vowel_regex = re.compile(r'[aeiouAEIOU]')
vowel_regex.findall('Robocop eats baby food. BABY FOOD.')
['o', 'o', 'o', 'e', 'a', 'a', 'o', 'o', 'A', 'O', 'O']

Você também pode incluir intervalos de letras ou números usando um hífen. Por exemplo, a classe de caracteres [a-zA-Z0-9] corresponderá a todas as letras minúsculas, letras maiúsculas e números.

Ao colocar um acento circunflexo (^) logo após o colchete de abertura da classe de caracteres, você pode criar uma classe de caracteres negativa que corresponderá a todos os caracteres que não estão na classe de caracteres:

consonant_regex = re.compile(r'[^aeiouAEIOU]')
consonant_regex.findall('Robocop eats baby food. BABY FOOD.')
['R', 'b', 'c', 'p', ' ', 't', 's', ' ', 'b', 'b', 'y', ' ', 'f', 'd', '.', ' ', 'B', 'B', 'Y', ' ', 'F', 'D', '.']

Os caracteres Caret e Dollar sign

  • Você também pode usar o símbolo de acento circunflexo ^ no início de um regex para indicar que uma correspondência deve ocorrer no início do texto pesquisado.

  • Da mesma forma, você pode colocar um cifrão $ no final do regex para indicar que a string deve terminar com este padrão regex.

  • E você pode usar o ^ e o $ juntos para indicar que a string inteira deve corresponder ao regex.

A string de expressão regular r'^Hello' corresponde a strings que começam com ‘Hello’:

begins_with_hello = re.compile(r'^Hello')
begins_with_hello.search('Hello world!')
<_sre.SRE_Match object; span=(0, 5), match='Hello'>
begins_with_hello.search('He said hello.') is None
True

A string de expressão regular r'\d\$' corresponde a strings que terminam com um caractere numérico de 0 a 9:

whole_string_is_num = re.compile(r'^\d+$')

whole_string_is_num.search('1234567890')
<_sre.SRE_Match object; span=(0, 10), match='1234567890'>
whole_string_is_num.search('12345xyz67890') is None
True
whole_string_is_num.search('12 34567890') is None
True

O caractere curinga (Wildcard)

O caractere . (ou ponto) em uma expressão regular corresponderá a qualquer caractere, exceto uma nova linha:

at_regex = re.compile(r'.at')

at_regex.findall('The cat in the hat sat on the flat mat.')
['cat', 'hat', 'sat', 'lat', 'mat']

Correspondendo tudo com Ponto-Asterisco

name_regex = re.compile(r'First Name: (.*) Last Name: (.*)')

mo = name_regex.search('First Name: Al Last Name: Sweigart')
mo.group(1)
'Al'
mo.group(2)
'Sweigart'

O .* usa modo guloso: Ele sempre tentará corresponder o máximo de texto possível. Para corresponder a qualquer texto de forma não-gulosa, use o ponto, asterisco e ponto de interrogação (.*?). O ponto de interrogação diz ao Python para corresponder de forma não-gulosa:

non_greedy_regex = re.compile(r'<.*?>')
mo = non_greedy_regex.search('<To serve man> for dinner.>')
mo.group()
'<To serve man>'
greedy_regex = re.compile(r'<.*>')
mo = greedy_regex.search('<To serve man> for dinner.>')
mo.group()
'<To serve man> for dinner.>'

Correspondendo novas linhas com o caractere Ponto

O ponto-asterisco corresponde a tudo, exceto uma nova linha. Ao passar re.DOTALL como o segundo argumento para re.compile(), você pode fazer com que o caractere ponto corresponda a todos os caracteres, incluindo o caractere de nova linha:

no_newline_regex = re.compile('.*')
no_newline_regex.search('Serve the public trust.\nProtect the innocent.\nUphold the law.').group()
'Serve the public trust.'
newline_regex = re.compile('.*', re.DOTALL)
newline_regex.search('Serve the public trust.\nProtect the innocent.\nUphold the law.').group()
'Serve the public trust.\nProtect the innocent.\nUphold the law.'

Correspondência sem distinção entre maiúsculas e minúsculas (Case-Insensitive)

Para tornar seu regex insensível a maiúsculas e minúsculas, você pode passar re.IGNORECASE ou re.I como segundo argumento para re.compile():

robocop = re.compile(r'robocop', re.I)

robocop.search('Robocop is part man, part machine, all cop.').group()
'Robocop'
robocop.search('ROBOCOP protects the innocent.').group()
'ROBOCOP'
robocop.search('Al, why does your programming book talk about robocop so much?').group()
'robocop'

Substituindo strings com o método sub()

O método sub() para objetos Regex recebe dois argumentos:

  1. O primeiro argumento é uma string para substituir quaisquer correspondências.
  2. O segundo é a string para a expressão regular.

O método sub() retorna uma string com as substituições aplicadas:

names_regex = re.compile(r'Agent \w+')

names_regex.sub('CENSORED', 'Agent Alice gave the secret documents to Agent Bob.')
'CENSORED gave the secret documents to CENSORED.'
Quiz

Faça login para responder este quiz e acompanhar seu progresso de aprendizagem

O que o método sub() faz?
A. Encontra todas as correspondências em uma string
B. Substitui todas as correspondências por uma string de substituição
C. Divide uma string nas correspondências
D. Valida o formato de uma string

Gerenciando Regexes complexos

Para instruir a função re.compile() a ignorar espaços em branco e comentários dentro da string de expressão regular, o “modo verboso” pode ser ativado passando a variável re.VERBOSE como o segundo argumento para re.compile().

Agora, em vez de uma expressão regular difícil de ler como esta:

phone_regex = re.compile(r'((\d{3}|\(\d{3}\))?(\s|-|\.)?\d{3}(\s|-|\.)\d{4}(\s*(ext|x|ext.)\s*\d{2,5})?)')

você pode espalhar a expressão regular por várias linhas com comentários como este:

phone_regex = re.compile(r'''(
    (\d{3}|\(\d{3}\))?            # código de área
    (\s|-|\.)?                    # separador
    \d{3}                         # primeiros 3 dígitos
    (\s|-|\.)                     # separador
    \d{4}                         # últimos 4 dígitos
    (\s*(ext|x|ext.)\s*\d{2,5})?  # extensão
    )''', re.VERBOSE)
Quiz

Faça login para responder este quiz e acompanhar seu progresso de aprendizagem

O que re.VERBOSE faz quando passado para re.compile()?
A. Permite espaços em branco e comentários no padrão regex para melhor legibilidade
B. Torna o regex insensível a maiúsculas e minúsculas
C. Faz com que o ponto corresponda a caracteres de nova linha
D. Acelera a correspondência regex