Introdução
Uma expressão regular, ou regex, é uma ferramenta poderosa para o processamento de texto. É uma sequência de caracteres que define um padrão de busca, permitindo encontrar, casar (match) e gerenciar texto com flexibilidade incrível. Em Python, a funcionalidade de expressões regulares é tratada pelo módulo re.
Neste laboratório, você aprenderá os fundamentos do uso de expressões regulares em Python. Começaremos com o básico de casar padrões e gradualmente avançaremos para tópicos mais avançados, como agrupamento, uso de quantificadores para repetição, definição de classes de caracteres e aproveitamento de métodos e flags poderosos para lidar com cenários de casamento complexos. Ao final, você se sentirá confortável usando regex para realizar operações sofisticadas em strings.
Introdução à Correspondência Regex
Nesta etapa, você aprenderá o fluxo de trabalho básico para usar expressões regulares (regex) em Python. O processo geralmente envolve quatro etapas principais:
- Importar o módulo
re. - Criar um objeto Regex usando
re.compile(). Recomenda-se o uso de uma raw string (r"...") para evitar que barras invertidas sejam interpretadas como caracteres de escape. - Usar o método
search()do objeto Regex para encontrar um padrão em uma string. Isso retorna um objetoMatchse o padrão for encontrado. - Usar o método
group()do objetoMatchpara obter o texto correspondente real.
Primeiro, vamos analisar alguns símbolos comuns de regex que você estará utilizando.
| Símbolo | Corresponde 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. |
^spam |
significa 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 \s |
um dígito, palavra, ou caractere de espaço, respectivamente. |
\D, \W, e \S |
qualquer 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. |
Agora, vamos colocar isso em prática. Escreveremos um script para encontrar um número de telefone em uma string. O padrão para um número de telefone dos EUA é XXX-XXX-XXXX, onde X é um dígito. Em regex, \d representa um dígito.
Nota: Se você não está familiarizado com o uso do WebIDE (semelhante ao VS Code), aprenda primeiro neste laboratório.
Abra o arquivo main.py no explorador de arquivos à esquerda e adicione o seguinte código.
## Importa o módulo re para operações de expressão regular
import re
## re.compile(): cria o objeto de padrão regex (use raw string r'' para evitar escape)
## O padrão \d\d\d-\d\d\d-\d\d\d\d corresponde a três dígitos, um hífen, três dígitos, um hífen e quatro dígitos.
phone_num_regex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')
## O método search() percorre a string, procurando a primeira localização onde este regex produz uma correspondência.
mo = phone_num_regex.search('My number is 415-555-4242.')
## O método group() retorna a string do texto correspondente.
print(f'Phone number found: {mo.group()}')
Para executar o script, abra um terminal e execute o seguinte comando:
python3 main.py
Você deverá ver o número de telefone correspondente impresso no console.
Phone number found: 415-555-4242
Este fluxo de trabalho básico é a fundação para todas as operações de regex em Python.
Agrupamento e Alternância
Nesta etapa, você aprenderá como isolar partes específicas do seu texto casado usando grupos e como casar uma de várias expressões possíveis usando alternância.
Agrupamento com Parênteses ()
Os parênteses () são usados para criar grupos dentro de uma expressão regular. Isso é útil quando você deseja extrair partes de um casamento (match), como o código de área de um número de telefone. Você pode acessar grupos individuais com group(n), onde group(1) é o primeiro grupo, group(2) é o segundo, e assim por diante. group(0) ou group() retorna a string inteira casada.
Vamos modificar main.py para separar o código de área do restante do número de telefone.
import re
## Parentheses create groups: group(1) for the first group, group(2) for the second.
## The first group (\d\d\d) captures the area code.
## The second group (\d\d\d-\d\d\d\d) captures the main number.
phone_num_regex = re.compile(r'(\d\d\d)-(\d\d\d-\d\d\d\d)')
mo = phone_num_regex.search('My number is 415-555-4242.')
## To retrieve all groups at once, use the groups() method, which returns a tuple.
area_code, main_number = mo.groups()
print(f"Area Code: {area_code}")
print(f"Main Number: {main_number}")
print(f"Full Match: {mo.group(0)}")
Execute o script:
python3 main.py
A saída mostrará as partes separadas do número:
Area Code: 415
Main Number: 555-4242
Full Match: 415-555-4242
Alternância com a Barra Vertical |
O caractere de barra vertical | funciona como um operador "OU" (OR). Ele permite que você case uma de várias expressões. Por exemplo, Batman|Tina Fey casará com "Batman" ou "Tina Fey".
Você também pode usar a barra vertical dentro de um grupo para casar um de vários padrões possíveis como parte da sua regex. Vamos tentar casar diferentes termos relacionados a "Bat-". Atualize seu main.py com o seguinte código:
import re
## The pipe | matches one of several patterns within a group.
## Here, it matches 'man', 'mobile', 'copter', or 'bat'.
bat_regex = re.compile(r'Bat(man|mobile|copter|bat)')
mo = bat_regex.search('Batmobile lost a wheel')
print(f"Full match: {mo.group()}")
print(f"Group 1: {mo.group(1)}")
Execute o script novamente:
python3 main.py
Você verá que a regex casou com "Batmobile", e o primeiro grupo capturou "mobile".
Full match: Batmobile
Group 1: mobile
Repetição com Quantificadores
Nesta etapa, exploraremos os quantificadores, que são caracteres especiais que permitem especificar quantas vezes um grupo precedente deve se repetir.
Casamento Opcional com ?
O ponto de interrogação ? torna o grupo precedente opcional, o que significa que ele casará zero ou uma vez. Isso é perfeito para padrões que podem ou não aparecer. Por exemplo, podemos casar tanto "Batman" quanto "Batwoman".
Atualize main.py com este código:
import re
## The (wo)? group is optional. It will match 'wo' if it exists, or match nothing if it doesn't.
bat_regex = re.compile(r'Bat(wo)?man')
mo1 = bat_regex.search('The Adventures of Batman')
print(mo1.group())
mo2 = bat_regex.search('The Adventures of Batwoman')
print(mo2.group())
Execute o script:
python3 main.py
A saída mostra que ambas as strings foram casadas com sucesso:
Batman
Batwoman
Zero ou Mais com *
O asterisco * (ou estrela) casa com o grupo precedente zero ou mais vezes. Isso é útil quando um padrão pode se repetir qualquer número de vezes, inclusive nenhuma.
import re
## The (wo)* group can appear zero or more times.
bat_regex = re.compile(r'Bat(wo)*man')
mo1 = bat_regex.search('The Adventures of Batman') ## Zero 'wo'
print(mo1.group())
mo2 = bat_regex.search('The Adventures of Batwowowowoman') ## Four 'wo's
print(mo2.group())
Um ou Mais com +
O sinal de mais + casa com o grupo precedente uma ou mais vezes. Diferente da estrela, o grupo deve aparecer pelo menos uma vez.
import re
## The (wo)+ group must appear at least once.
bat_regex = re.compile(r'Bat(wo)+man')
mo1 = bat_regex.search('The Adventures of Batwoman') ## One 'wo'
print(mo1.group())
mo2 = bat_regex.search('The Adventures of Batman') ## Zero 'wo's
print(mo2 is None) ## This will print True because no match is found.
Repetições Específicas com {}
As chaves {} permitem que você especifique um número exato de repetições, ou um intervalo.
{3}casa exatamente três vezes.{3,5}casa entre três e cinco vezes.{3,}casa três ou mais vezes.{,5}casa até cinco vezes.
import re
## (Ha){3} matches 'Ha' repeated exactly 3 times.
ha_regex = re.compile(r'(Ha){3}')
mo1 = ha_regex.search('HaHaHa')
print(mo1.group())
Casamento Ganancioso (Greedy) e Não Ganancioso (Non-Greedy)
Por padrão, a regex do Python é "gananciosa" (greedy), o que significa que ela casa com a string mais longa possível. Para torná-la "não gananciosa" (non-greedy) (casar com a string mais curta possível), adicione um ponto de interrogação ? após o quantificador.
Vamos ver a diferença. Limpe main.py e adicione o seguinte:
import re
## Greedy match: {3,5} matches the longest possible string (5 'Ha's).
greedy_ha_regex = re.compile(r'(Ha){3,5}')
mo1 = greedy_ha_regex.search('HaHaHaHaHa')
print(f"Greedy match: {mo1.group()}")
## Non-greedy match: {3,5}? matches the shortest possible string (3 'Ha's).
non_greedy_ha_regex = re.compile(r'(Ha){3,5}?')
mo2 = non_greedy_ha_regex.search('HaHaHaHaHa')
print(f"Non-greedy match: {mo2.group()}")
Execute o script:
python3 main.py
A saída mostra claramente a diferença:
Greedy match: HaHaHaHaHa
Non-greedy match: HaHaHa
Classes de Caracteres, Âncoras e Curingas
Nesta etapa, você aprenderá técnicas mais avançadas, incluindo encontrar todos os casamentos (matches), criar conjuntos de caracteres personalizados, ancorar casamentos ao início ou fim de uma string e usar curingas.
O Método findall()
Enquanto search() retorna apenas o primeiro casamento, o método findall() retorna uma lista de todos os casamentos não sobrepostos na string. Se a regex tiver grupos, findall() retorna uma lista de tuplas, onde cada tupla contém as strings para cada grupo.
Atualize main.py com este exemplo:
import re
## If the regex has no groups, findall() returns a list of strings.
phone_num_regex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')
matches = phone_num_regex.findall('Cell: 415-555-9999 Work: 212-555-0000')
print(matches)
Execute o script para ver a saída:
python3 main.py
['415-555-9999', '212-555-0000']
Criando Suas Próprias Classes de Caracteres []
Os colchetes [] permitem definir uma classe de caracteres personalizada que casará com qualquer caractere único dentro dela. Por exemplo, [aeiou] casa com qualquer vogal minúscula. Você também pode especificar um intervalo, como [a-z] para qualquer letra minúscula ou [0-9] para qualquer dígito.
Um acento circunflexo ^ como o primeiro caractere dentro dos colchetes cria uma classe de caracteres negativa, que casa com qualquer caractere que não esteja na classe.
Vamos encontrar todas as vogais em uma string. Atualize main.py:
import re
## [aeiouAEIOU] matches any vowel, lowercase or uppercase.
vowel_regex = re.compile(r'[aeiouAEIOU]')
vowels = vowel_regex.findall('Robocop eats baby food. BABY FOOD.')
print(vowels)
Âncoras: Acento Circunflexo ^ e Sinal de Dólar $
Âncoras são usadas para afirmar uma posição na string.
- O acento circunflexo
^casa com o início da string. - O sinal de dólar
$casa com o fim da string.
Quando usadas juntas (^...$), elas forçam que a string inteira corresponda ao padrão.
import re
## ^Hello matches strings that start with 'Hello'.
begins_with_hello = re.compile(r'^Hello')
match1 = begins_with_hello.search('Hello world!')
print(match1 is not None) ## True
## \d+$ matches strings that end with one or more digits.
ends_with_number = re.compile(r'\d+$')
match2 = ends_with_number.search('Your number is 42')
print(match2.group()) ## '42'
## ^\d+$ matches strings that consist only of digits.
whole_string_is_num = re.compile(r'^\d+$')
match3 = whole_string_is_num.search('1234567890')
print(match3 is not None) ## True
O Caractere Curinga .
O ponto . (ou curinga) casa com qualquer caractere único, exceto uma quebra de linha (newline). É um atalho útil para "qualquer caractere".
Vamos encontrar todas as palavras de três letras terminadas em "at". Atualize main.py:
import re
## The . character matches any character (except newline).
## So, .at matches 'cat', 'hat', 'sat', etc.
at_regex = re.compile(r'.at')
matches = at_regex.findall('The cat in the hat sat on the flat mat.')
print(matches)
Execute o script:
python3 main.py
A saída será uma lista de todas as palavras casadas:
['cat', 'hat', 'sat', 'lat', 'mat']
Métodos Avançados e Flags
Nesta etapa final, abordaremos alguns métodos e flags poderosos que modificam o comportamento das suas expressões regulares (regular expressions), tornando-as ainda mais versáteis.
Casando com Tudo com Ponto-Estrela .*
A combinação .* é um padrão comum que casa com qualquer caractere (.) repetido zero ou mais vezes (*). É usada para casar com qualquer sequência de caracteres. Por padrão, é gananciosa (greedy) e casará com o máximo de texto possível.
import re
## The pattern (.*) captures everything between 'First Name: ' and ' Last Name: '.
name_regex = re.compile(r'First Name: (.*) Last Name: (.*)')
mo = name_regex.search('First Name: Al Last Name: Sweigart')
print(f"First Name: {mo.group(1)}")
print(f"Last Name: {mo.group(2)}")
Para torná-lo não ganancioso (non-greedy), use .*?. Isso casará com a string mais curta possível.
Casando com Quebras de Linha com re.DOTALL
Por padrão, o caractere ponto . não casa com caracteres de quebra de linha (\n). Para mudar isso, você pode passar re.DOTALL como um segundo argumento para re.compile(). Este flag permite que . case com todos os caracteres, incluindo quebras de linha.
import re
## With re.DOTALL, '.*' will match across multiple lines.
newline_regex = re.compile('.*', re.DOTALL)
mo = newline_regex.search('Serve the public trust.\nProtect the innocent.\nUphold the law.')
print(mo.group())
Casamento Insensível a Maiúsculas/Minúsculas com re.IGNORECASE
Para fazer sua regex ignorar o caso (por exemplo, casar com "cat", "Cat" e "CAT"), passe re.IGNORECASE ou seu atalho re.I como o segundo argumento para re.compile().
import re
## re.I makes the pattern 'robocop' match 'Robocop', 'ROBOCOP', etc.
robocop = re.compile(r'robocop', re.I)
match = robocop.search('Robocop is part man, part machine, all cop.')
print(match.group())
Substituindo Strings com o Método sub()
O método sub() encontra todas as ocorrências de um padrão e as substitui por uma string especificada. Ele aceita dois argumentos: a string de substituição e a string a ser pesquisada.
Vamos substituir nomes de agentes por "CENSORED". Atualize main.py:
import re
## The pattern 'Agent \w+' matches 'Agent ' followed by one or more word characters.
names_regex = re.compile(r'Agent \w+')
result = names_regex.sub('CENSORED', 'Agent Alice gave the secret documents to Agent Bob.')
print(result)
Execute o script:
python3 main.py
A saída mostrará a string substituída:
CENSORED gave the secret documents to CENSORED.
Gerenciando Regexes Complexas com re.VERBOSE
Quando os padrões de regex se tornam complexos, podem ser difíceis de ler. Ao passar re.VERBOSE para re.compile(), você pode escrever sua regex em múltiplas linhas e adicionar comentários para explicar as diferentes partes. Espaços em branco e comentários (#) dentro da string são ignorados.
Esta regex complexa:
phone_regex = re.compile(r'((\d{3}|\(\d{3}\))?(\s|-|\.)?\d{3}(\s|-|\.)\d{4}(\s*(ext|x|ext.)\s*\d{2,5})?)')
Torna-se esta versão legível com re.VERBOSE:
import re
phone_regex = re.compile(r'''(
(\d{3} | \(\d{3}\))? ## area code (optional)
(\s | - | \.)? ## separator (optional)
\d{3} ## first 3 digits
(\s | - | \.) ## separator
\d{4} ## last 4 digits
(\s*(ext|x|ext.)\s*\d{2,5})? ## extension (optional)
)''', re.VERBOSE)
mo = phone_regex.search("My phone number is 415-555-4242 ext. 55")
if mo:
print(f"Found: {mo.group()}")
Isso torna seu código muito mais fácil de manter.
Resumo
Neste laboratório, você dominou os fundamentos das expressões regulares (regular expressions) em Python usando o módulo re. Você aprendeu o fluxo de trabalho completo, desde a compilação de um padrão com re.compile() até encontrar casamentos (matches) com search() e recuperar o texto com group().
Você explorou conceitos chave, incluindo:
- Agrupamento (Grouping) com
()para capturar partes específicas de um casamento. - Alternância (Alternation) com
|para casar com um de vários padrões. - Quantificadores (Quantifiers) como
?,*,+e{}para controlar a repetição. - Casamento Ganancioso (Greedy) vs. Não Ganancioso (Non-greedy) para controlar o comprimento dos casamentos.
- Ferramentas avançadas como
findall()para obter todos os casamentos, classes de caracteres[]para conjuntos personalizados, e âncoras^e$para fixar casamentos aos limites da string. - Flags poderosos como
re.DOTALLpara casamentos multilinhas,re.IGNORECASEpara insensibilidade a maiúsculas/minúsculas ere.VERBOSEpara escrever regexes limpas e comentadas. - Substituição de strings com o método
sub().
Com essas habilidades, você está agora equipado para lidar com uma ampla gama de tarefas de processamento de texto, desde validação simples de dados até extração e manipulação complexa de dados.



