Tutorial sobre Expressões Regulares para iniciantes em Python

Traduzido do artigo “Beginners Tutorial for Regular Expressions in Python

Autor: Sunil Ray

Importância das Expressões Regulares

Nos últimos anos, houve muitas mudanças no uso de linguagens de programação de propósito geral para data science e machine learning. Nem sempre foi assim – há dez anos atrás essa afirmação teria como resposta muito ceticismo.

Isso significa que cada vez mais pessoas e organizações estão usando ferramentas como Python e JavaScript para tratar suas necessidades relativas a dados. Expressões regulares são normalmente o meio padrão para limpar e tratar dados nessas ferramentas. Seja extração de partes específicas de textos de páginas html, obtenção de informação sobre dados do Twitter or preparação de dados para mineração de textos – Expressões Regulares são a melhor aposta para resolver todas essas questões.

Dada sua aplicabilidade, faz sentido conhecer bem Expressões Regulares e saber como usá-las de modo apropriado.

O que você irá aprender com esse artigo?

Neste artigo, vou mostrar para você uso, exemplos e aplicações de Expressões Regulares – ou Regex. Regex é muito popular entre programadores e pode ser aplicada em muitas linguagens de programação como Java, JS, PHP, C++, etc. Para melhor entendimento, vamos explicar esse conceito usando Python. Ao final, resolvo diversos problemas usando Regex.

Vamos começar!

O que são Expressões Regulares e como são usadas?

Dito de forma simples, expressão regular é uma sequência de caracteres usados principalmente para encontrar e substituir padrões numa string ou num arquivo. Como dito anteriormente, a maioria das linguagens de programação como Python, Perl, R, Java e muitas outras suportam regex. Então, aprender regex ajuda de múltiplas maneiras (mais sobre isso depois).

Expressões regulares usam dois tipos de caracteres:

  1. Meta-caracteres: como o nome sugere, esses caracteres têm significado especial, similar ao * numa carta coringa.
  2. Literais: como a, b, 1, 2…

Em Python, temos o módulo “re” que ajuda com as expressões regulares. Você precisa primeiro importar a biblioteca re para então poder usar regex no Python.

Import re

Os usos mais comuns de regex são:

  • Buscar uma string (search e match)
  • Achar uma string (findall)
  • Quebrar uma string em sub strings (split)
  • Substituir parte de uma string (sub)

Vamos olhar os métodos que a biblioteca re fornece para desempenhar essas atividades.

Nota: temos também um curso em vídeo sobre Processamento de Linguagem Natural (NLP) que cobre regex também. Dê uma olhada!

Quais são os vários métodos de Expressões Regulares?

O pacote ‘re’ fornece múltiplos métodos para rodar queries numa string. Aqui segue os métodos mais comumente usados, os quais iremos discutir:

  1. re.match()
  2. re.search()
  3. re.findall()
  4. re.split()
  5. re.sub()
  6. re.compile()

Vamos olhar um por um.

re.match(padrão, string)

Esse método encontra equivalência se ela ocorrer no início da string. Por exemplo, chamar match() na string ‘AV Analytics AV’ e buscar por um padrão ‘AV’ vai retornar uma equivalência. Contudo, se buscarmos por ‘Analytics’, não encontrará um padrão equivalente. Vamos ver funcionando no Python.

Código

import re 
result = re.match(r'AV', 'AV Analytics Vidhya AV')
print result

Resultado:
<_sre.SRE_Match object at 0x0000000009BE4370>

Acima, mostra que o padrão equivalente foi encontrado. Para retornar a string correspondente vamos usar o método group(). Use ‘r’ no começo da string padrão para designar ao Python uma string raw.

result = re.match(r'AV', 'AV Analytics Vidhya AV') 
print result.group(0)

Resultado:
AV

Vamos agora buscar por ‘Analytics’ na string de exemplo. Aqui vemos que a string raw não começa com ‘AV’ e por isso não deveria retornar nenhum resultado. Vamos ver o que obtemos:

Código

result = re.match(r'Analytics', 'AV Analytics Vidhya AV') 
print result

Resultado:
None

Existem métodos como start() e end() para definir a posição de começo e de fim padrão buscado na string.

Código

result = re.match(r'AV', 'AV Analytics Vidhya AV') 
print result.start()
print result.end()

Resultado:
0
2

Acima podemos ver a posição de começo e de fim do padrão ‘AV’ na string e às vezes isso ajuda muito enquanto manipulamos strings.

re.search(padrão, string)

É similar a match() mas não nos restringe a encontrar equivalência apenas no começo da string. Diferente de métodos anteriores, aqui a busca pelo padrão “Analytics” irá retornar resultado positivo.

Código

result = re.search(r'Analytics', 'AV Analytics Vidhya AV') 
print result.group(0)

Resultado:
Analytics

Aqui podemos ver que o método search() consegue encontrar um padrão em qualquer posição da string mas que somente retorna a primeira ocorrência do padrão de busca.

re.findall(padrão, string)

É útil obter uma lista de todos os padrões encontrados. Não há restrições em buscar do começo ou do fim. Se usarmos o método findall para buscar por ‘AV’ numa dada string, irá retornar amboas ocorrências de AV. Quando efetuar buscas numa string, recomendo usar re.findall() sempre, funciona como ambas re.search() e re.match().

Código

result = re.findall(r'AV', 'AV Analytics Vidhya AV') 
print result

Resultado:
['AV', 'AV']

re.split(padrão, string)

Este método ajuda a dividir a string pela ocorrências do padrão dado.

Código

result=re.split(r'y','Analytics') 
print result

Resultado:
['Anal', 'tics']

Acima, dividimos a a string “Analytics” por “y”. O método split() tem um argumento chamado “maxsplit”. Seu valor padrão é zero. Nesse caso, faz o máximo de divisões possíveis, mas se dermos um valor para maxsplit, ele dividirá a string. Vamos ver o exemplo abaixo:

Código

result=re.split(r'i','Analytics Vidhya') 
print result

Resultado: ['Analyt', 'cs V', 'dhya'] #Realizou todas as divisões possíveis para o padrão "i".

Código
result=re.split(r'i','Analytics Vidhya', maxsplit=1)
print result

Resultado:
['Analyt', 'cs Vidhya']

Aqui você pode notar que fixamos maxsplit em 1. E o resultado é que só tem 2 valores enquanto o primeiro exemplo tem 3 valores.

re.sub(padrão, string)

Às vezes é útil buscar um padrão de string e substituí-lo por uma nova sub-string. Se o padrão não for encontrado, a string é retornada sem mudanças.

Código

result=re.sub(r'da India','do Mundo','AV é a maior comunidade de Analytics da India') 
print result

Resultado:
'AV é a maior comunidade de Analytics do Mundo'

re.compile(padrão, string)

Podemos combinar uma expressão regular com objetos de padrões, que pode ser usado para encontrar padrões. É útil também para buscar um padrão sem ter que re-escrevê-lo.

Código

import re 
pattern=re.compile('AV')
result=pattern.findall('AV Analytics Vidhya AV')
print result
result2=pattern.findall('AV é a maior comunidade de Analytics da India')
print result2

Resultado:
['AV', 'AV']
['AV']

Revendo os principais métodos

Até agora, olhamos vários métodos de expressões regulares usando padrões constantes (caracteres fixos). Todavia, e se não tivermos que buscar um padrão constante e quisermos retornar conjuntos específicos de caracteres (definidos a partir de uma regra) a partir de uma string? Não se deixe intimidar.
Isso pode ser facilmente resolvido em se definindo uma expressão com a ajuda de operadores de padrões (meta-caracteres e caracteres literais). Vejamos os operadores mais comuns.

Quais são os operadores mais comuns?

Expressões regulares podem especificar padrões e não somente caracteres fixos. Aqui temos os operadores mais comumente usados e que ajudam a gerar uma expressão para representar os caracteres requeridos numa string ou num arquivo. É muito usado em scraping de páginas web e mineração de textos para extrair as informações requeridas.

Operadores Descrição
. Corresponde a qualquer caractere único, exceto a nova linha “\ n”.
? Corresponde a 0 ou uma ocorrência do padrão, encontrada à esquerda
+ Corresponde a uma ou mais ocorrências do padrão, encontradas à esquerda
* Corresponde a 0 ou mais ocorrências do padrão, encontradas à esquerda
\w Corresponde a um caracter alfanumérico
\W Corresponde a um caracter não-alfanumérico
\d Encontra dígitos [0-9]
\D Encontra não-dígitos
\s Corresponde com caracter único de espaço em branco (espaço, nova linha, retorno, tab, from)
\S Corresponde a qualquer caracter que não espaço em branco
\b Fronteira entre palavra e não-palavra
\B Oposto de \b
[..] Corresponde com qualquer caracter único nos colchetes e [^…] corresponde a qualquer caracter único fora dos colchetes
[^…] Corresponde a qualquer caracter único fora dos colchetes
\ Usado para caracteres de significado especial como \. para corresponder a um período ou \+ para sinal +
^ e $ ^ e $ correspondem ao início e final da string, respectivamente
{n, m} Encontra pelo menos n e no máximo m ocorrências da expressão precedente, se escrevermos com {,m} então irá retornar pelo menos qualquer mínima ocorrência até no máximo m da expressão precedente
a | b Corresponde a a ou b
() Agrupa expressões regulares e retorna o texto correspondente
\t, \n, \r Corresponde a tab, nova linha, retorno

Para mais detalhes sobre meta-caracteres “(“,”)”,”I” e outros detalhes, você pode ir para esse link (https://docs.python.org/2/library/re.html).

Agora, vamos entender sobre os operadores através dos exemplos a seguir.

Alguns exemplos de Expressões Regulares

Problema 1: Retornar a primeira palavra de uma dada string

Solução-1 Extrair cada caracter (usando “\w”)
Código

import re 
result=re.findall(r'.','AV is largest Analytics community of India')
print result

Rsultado:
['A', 'V', ' ', 'i', 's', ' ', 'l', 'a', 'r', 'g', 'e', 's', 't', ' ', 'A', 'n', 'a', 'l', 'y', 't', 'i', 'c', 's', ' ', 'c', 'o', 'm', 'm', 'u', 'n', 'i', 't', 'y', ' ', 'o', 'f', ' ', 'I', 'n', 'd', 'i', 'a']

Acima, o espaço também foi extraído, então para evitar isso use “\w” ao invés de “.”.
Código

result=re.findall(r'\w','AV is largest Analytics community of India') 
print result

Resultado:
['A', 'V', 'i', 's', 'l', 'a', 'r', 'g', 'e', 's', 't', 'A', 'n', 'a', 'l', 'y', 't', 'i', 'c', 's', 'c', 'o', 'm', 'm', 'u', 'n', 'i', 't', 'y', 'o', 'f', 'I', 'n', 'd', 'i', 'a']

Solução-2 Extrair cada palavra usando “*” or “+”
Código

result=re.findall(r'\w*','AV is largest Analytics community of India') 
print result

Resultado:
['AV', '', 'is', '', 'largest', '', 'Analytics', '', 'community', '', 'of', '', 'India', '']

Novamente, retorna espaço como uma palavra porque “*” retorna zero ou mais correspondências do padrão à esquerda. Agora vamos remover os espaços com “+”.
Código

result=re.findall(r'\w+','AV is largest Analytics community of India') 
print result

Resultado:
['AV', 'is', 'largest', 'Analytics', 'community', 'of', 'India']

Solução-3 Extrair cada palavra usando “^”
Código

result=re.findall(r'^\w+','AV is largest Analytics community of India') 
print result

Resultado:
['AV']

Se usarmos “$” ao invés de “^”, irá retornar a palavra do final da string. Vamos ver.
Codigo

result=re.findall(r'\w+$','AV is largest Analytics community of India') 
print result

Resultado:
[‘India’]

Problema 2: Retornar os dois primeiros caracteres de cada palavra

Solução 1- Extrair 2 caracteres consecutivos de cada palavra, excluindo espaços e usando “\w”
Código

result=re.findall(r'\w\w','AV is largest Analytics community of India') 
print result

Resultado:
['AV', 'is', 'la', 'rg', 'es', 'An', 'al', 'yt', 'ic', 'co', 'mm', 'un', 'it', 'of', 'In', 'di']

Solução 2- extrair 2 caracteres consecutivos dos constantes no início de cada palavra e usando “\b”
Código

result=re.findall(r'\b\w.','AV is largest Analytics community of India') 
print result

Resultado:
['AV', 'is', 'la', 'An', 'co', 'of', 'In']

Problema 3: Retornar o domínio de emails

Para explicar de modo simples, seguiremos uma abordagem passo a passo:

Solução 1- Extrair todos os caracteres depois de “@”
Código

result=re.findall(r'@\w+','abc.test@gmail.com, xyz@test.in, test.first@analyticsvidhya.com, first.test@rest.biz')  
print result

Resultado:
['@gmail', '@test', '@analyticsvidhya', '@rest']

Acima, você pode ver que a parte “.com” não foi extraída. Para adicioná-la, use o código abaixo.

result=re.findall(r'@\w+.\w+','abc.test@gmail.com, xyz@test.in, test.first@analyticsvidhya.com, first.test@rest.biz') 
print result

Resultado:
['@gmail.com', '@test.in', '@analyticsvidhya.com', '@rest.biz']

Solução 2- Extrair somente o domínio usando “()”
Código

result=re.findall(r'@\w+.(\w+)','abc.test@gmail.com, xyz@test.in, test.first@analyticsvidhya.com, first.test@rest.biz') 
print result

Resultado:
['com', 'in', 'com', 'biz']

Problema 4: Retornar a data de uma string

Aqui usaremos “\d” para extrair os dígitos.

Solução
Código

result=re.findall(r'\d{2}-\d{2}-\d{4}','Amit 34-3456 12-05-2007, XYZ 56-4532 11-11-2011, ABC 67-8945 12-01-2009') 
print result

Resultado:
['12-05-2007', '11-11-2011', '12-01-2009']

Se quiser extrair apenas o ano, parênteses novamente irá resolver.
Código

result=re.findall(r'\d{2}-\d{2}-(\d{4})','Amit 34-3456 12-05-2007, XYZ 56-4532 11-11-2011, ABC 67-8945 12-01-2009') 
print result

Resultado:
['2007', '2011', '2009']

Problema 5: Retornar todas as palavras de uma string que se iniciam com vogais

Solução 1- Retorna cada palavra
Código

result=re.findall(r'\w+','AV is largest Analytics community of India') 
print result

Resultado:
['AV', 'is', 'largest', 'Analytics', 'community', 'of', 'India']

Solução 2- Retorna palavras começando com vogais, usando ‘[]’
Código

result=re.findall(r'[aeiouAEIOU]\w+','AV is largest Analytics community of India') 
print result

Output:
['AV', 'is', 'argest', 'Analytics', 'ommunity', 'of', 'India']

Acima, você pode notar que retornou “argest” e “ommunity”. Para eliminar essas duas, precisamos usar “\b” como fronteira de palavra.

Solução 3-
Código

result=re.findall(r'\b[aeiouAEIOU]\w+','AV is largest Analytics community of India') 
print result 

Resultado:
['AV', 'is', 'Analytics', 'of', 'India']

De modo similar, podemos extrair palavras cujos inícios são com constantes usando “^” dentro dos colchetes.

Código

result=re.findall(r'\b[^aeiouAEIOU]\w+','AV is largest Analytics community of India') 
print result

Resultado:
[' is', ' largest', ' Analytics', ' community', ' of', ' India']

Acima, você pode notar que retornou palavras começando com espaço. Para tirá-las do resultado, inclua espaço nos colchetes.

Código

result=re.findall(r'\b[^aeiouAEIOU ]\w+','AV is largest Analytics community of India') 

print result

Resultado:
['largest', 'community']

Problema 6: Validar um número de telefone (número deve ter 10 dígitos e começar com 8 ou 9)

Temos uma lista de números de telefone na lista “li” e iremos validar os números usando regex

Solução
Código

import re 
li=['9999999999','999999-999','99999x9999']
for val in li:
if re.match(r'[8-9]{1}[0-9]{9}',val) and len(val) == 10:
print 'sim'
else:
print 'não'


Resultado:
sim
não
não

Problema 7: Dividir uma string com múltiplos delimitadores

Solução
Código

import re 
line = 'asdf fjdk;afed,fjek,asdf,foo' # String has multiple delimiters (";",","," ").
result= re.split(r'[;,\s]', line)
print result

Resultado:
['asdf', 'fjdk', 'afed', 'fjek', 'asdf', 'foo']

Podemos usar também o método re.sub() para substituir esses múltiplos delimitadores por apenas um como ‘espaço’.

Código

import re 
line = 'asdf fjdk;afed,fjek,asdf,foo'
result= re.sub(r'[;,\s]',' ', line)
print result

Resultado:
asdf fjdk afed fjek asdf foo

Problema 8: Recuperar informação de um arquivo HTML

Quero extrair informações de um arquivo HTML (veja exemplo a seguir). Aqui precisamos extrair a informação disponível entre <td> e </td> com exceção do primeiro índice numérico. Aqui assumi que o código HTML abaixo foi armazenado numa string str.

Amostra de arquivo HTML (str)

<tr align="center"><td>1</td> <td>Noah</td> <td>Emma</td></tr> 
<tr align="center"><td>2</td> <td>Liam</td> <td>Olivia</td></tr>
<tr align="center"><td>3</td> <td>Mason</td> <td>Sophia</td></tr> <tr align="center"><td>4</td> <td>Jacob</td> <td>Isabella</td></tr> <tr align="center"><td>5</td> <td>William</td> <td>Ava</td></tr>
<tr align="center"><td>6</td> <td>Ethan</td> <td>Mia</td></tr>
<tr align="center"><td>7</td> <td HTML>Michael</td> <td>Emily</td></tr>

Solução
Código

result=re.findall(r'<td>\w+</td>\s<td>(\w+)</td>\s<td>(\w+)</td>',str) 
print result

Resultado:
[('Noah', 'Emma'), ('Liam', 'Olivia'), ('Mason', 'Sophia'), ('Jacob', 'Isabella'), ('William', 'Ava'), ('Ethan', 'Mia'), ('Michael', 'Emily')]

Você pode ler o arquivo HTML usando a biblioteca urllib2 (veja código a seguir).

Código

import urllib2 
response = urllib2.urlopen('')
html = response.read()

Notas finais

Neste artigo, discutimos sobre a expressão regular, os métodos e meta-caracteres que formam uma expressão regular. Olhamos também vários exemplos sobre usos práticos de regex. Aqui tentei apresentar a você expressões regulares e cobrir alguns métodos comuns para resolver boa parte dos problemas de expressões regulares.

Acho o artigo útil? Conte-nos o que achou deste guia nos comentários abaixo.


Veja também: