Pular para o conteúdo

Expressões Regulares

Introdução

O módulo re do Python permite identificar padrões dentro de strings. Esse recurso é bastante usado na análise dos dados coletados na raspagem de dados (web scraping). Basicamente, o programa fornece a string e o padrão a ser procurado, o Python então verifica se há uma combinação.

São exemplos de métodos/atributos disponibilizados pelo módulo re:

  • findall() – retorna uma lista de todas as correspondências encontradas;
  • search() – retorna a primeira correspondência encontrada;
  • match() – verifica se o padrão combina com o início do alvo;
  • split() – divide a string em uma lista, dividindo-a onde quer que haja correspondência com o padrão;
  • sub() – encontra todas as substrings que correspondem com o padrão e faz a substituição por uma string diferente.

Como exemplo, considere o módulo re e a variável msg que possui uma string (usado como o alvo).

import re
msg="""E agora, José? 
A festa acabou, a luz apagou, o povo sumiu, a noite esfriou, 
e agora, José? e agora, você? 
você que é sem nome, que zomba dos outros, 
você que faz versos, que ama, protesta?

Podemos verificar se o padrão “José” existe no alvo da seguinte forma:

padrao = 'José'
exp = re.compile(padrao)
resultado = exp.findall(msg)
print(resultado)

Neste caso, a expressão regular ‘José’ é compilada no objeto padrão exp. O método findall() procura pelo padrão (‘José’) no alvo (‘msg’) e retorna o resultado. A resposta é

['José', 'José', 'José']

É possível definir que o padrão não é case sensitive com

exp = re.compile(padrao, re.IGNORECASE)

Assim, o programa dará a mesma resposta, mesmo que a variável padrao seja igual a ‘JOSÉ’. Abaixo, é mostrada outra forma de pesquisar pelo padrão sem usar re.compile(). O resultado obtido pelo programa é o mesmo.

padrao = 'JOSÉ'
resultado = re.findall(padrao, msg, re.IGNORECASE)
print(resultado)

Para mais detalhes sobre expressões regulares em Python, veja https://docs.python.org/pt-br/3.8/howto/regex.html.

Metacaracteres

Um metacaractere é um caractere que tem um significado especial para o programa.

  • Ponto: .

     Esse metacaractere substitui um único caractere. Veja o exemplo abaixo.

import re
msg="""E agora, José? 
A festa acabou, a luz apagou, o povo sumiu, a noite esfriou, 
e agora, José? e agora, você? 
você que é sem nome, que zomba dos outros, 
você que faz versos, que ama, protesta? 
e agora, José?"""

padrao1 = 'a.a.ou'
resposta = re.findall(padrao1, msg)
print("*** Padrão 1")
print(resposta, "\n")

padrao2 = '....ou'
resposta = re.findall(padrao2, msg)
print("*** Padrão 2")
print(resposta)

     A resposta é

*** Padrão 1
['acabou', 'apagou'] 

*** Padrão 2
['acabou', 'apagou', 'sfriou', 'dos ou']

     Portanto, o primeiro padrão procura por uma substring com 6 caracteres onde o primeiro e o terceiro caracteres são ‘a’ e o quinto e o sexto caracteres correspondem a ‘ou’. O segundo padrão procura uma substring de 6 caracteres onde o quinto e o sexto caracteres correspondem a ‘ou’.

  • Lista: [ ]

     Esse metacaractere permite definir um conjunto de caracteres que pode aparecer na posição especificada.

import re
msg="""E agora, José? 
A festa acabou, a luz apagou, o povo sumiu, a noite esfriou, 
e agora, José? e agora, você? 
você que é sem nome, que zomba dos outros, 
você que faz versos, que ama, protesta? 
e agora, José?"""

padrao1 = 'a[abc]a[abc]ou'
resposta = re.findall(padrao1, msg)
print("*** Padrão 1")
print(resposta, "\n")

padrao2 = 'a[a-z]a[bg]ou'
resposta = re.findall(padrao2, msg)
print("*** Padrão 2")
print(resposta, "\n")

padrao3 = 'a[^c]a[a-z]ou'
resposta = re.findall(padrao3, msg)
print("*** Padrão 3")
print(resposta, "\n")

padrao4 = 'Jos[a-zá-ü]'
resposta = re.findall(padrao4, msg)
print("*** Padrão 4")
print(resposta, "\n")

     O primeiro padrão define que os caracteres ‘a’, ‘b’ e ‘c’ podem aparecer na segunda e na terceira posições. O segundo padrão permite que qualquer letra minúscula apareça na segunda posição e que os caracteres ‘b’ e ‘g’ podem aparecer na quarta posição. O terceiro padrão define que o caractere ‘c’ não pode aparecer na segunda posição e que qualquer letra minúscula pode aparecer na quarta posição. O quarto padrão especifica que qualquer letra minúscula, acentuada ou não, pode aparecer após “Jos”. O programa mostra a resposta abaixo.

*** Padrão 1
['acabou'] 

*** Padrão 2
['acabou', 'apagou'] 

*** Padrão 3
['apagou'] 

*** Padrão 4
['José', 'José', 'José'] 

     A tabela abaixo mostra exemplos de conjunto de caracteres que pode ser usado para substituir as classes POSIX (não definidas no Python).

Classe PosixPythonSignificado
[:upper:][A-ZÀ-Ü]Letras maiúsculas
(com e sem acentuação)
[:lower:][a-zà-ü]Letras minúsculas
(com e sem acentuação)
[:alpha:][A-Za-zÀ-ü]Maiúsculas/minúsculas
(com e sem acentuação)
[:alnum:][A-Za-zÀ-ü0-9]Letras e números
[:digit:][0-9]Números
  • Lista negada: [^]

     No exemplo acima, o terceiro padrão define que o caractere ‘c’ não pode aparecer na segunda posição com [^c]. Por isso a resposta mostra apenas a substring ‘apagou’ (não mostra ‘acabou’). Se o programa tivesse usado o padrão [^cp], nem “c’ e nem ‘p’ poderiam aparecer na segunda posição e a resposta da busca seria uma lista vazia.

  • Opcional: ?

     Esse metacaractere define que o caractere antes de ? pode ou não existir no padrão.

import re
msg="naturalmente, a natureza é natural e natureba"

padrao1 = 'natura?'
resposta = re.findall(padrao1, msg)
print("*** Padrão 1")
print(resposta, "\n")

padrao2 = 'nature?'
resposta = re.findall(padrao2, msg)
print("*** Padrão 2")
print(resposta, "\n")

padrao3 = 'natureb?a'
resposta = re.findall(padrao3, msg)
print("*** Padrão 3")
print(resposta, "\n")

padrao4 = 'nature[a-z]?'
resposta = re.findall(padrao4, msg)
print("*** Padrão 4")
print(resposta, "\n")

     O primeiro padrão procura por “natur” e “natura” no alvo. O segundo padrão procura por “natur” e “nature”. O terceiro padrão procura por “natureba” e “naturea”. O quarto padrão procura por uma substring que começa por “nature” e pode ter um caractere qualquer na sétima posição. A resposta é

*** Padrão 1
['natura', 'natur', 'natura', 'natur'] 

*** Padrão 2
['natur', 'nature', 'natur', 'nature'] 

*** Padrão 3
['natureba']

*** Padrão 4
['naturez', 'natureb'] 
  • Asterisco: *

     Esse metacaractere define que o caractere antes de * pode ocorrer zero, uma ou mais vezes.

import re
msg='1227 122228 104 1222222226 1632323'

padrao1 = '12*6'
resposta = re.findall(padrao1, msg)
print("*** Padrão 1")
print(resposta, "\n")

padrao2 = '12*'
resposta = re.findall(padrao2, msg)
print("*** Padrão 2")
print(resposta, "\n")

     O primeiro padrão procura por substrings que começam com ‘1’, têm uma quantidades indefinida de caracteres ‘2’ e no final têm o caractere ‘6’. O segundo padrão começa com ‘1’ e tem, em seguida, um numero indefinido de caracteres ‘2’.

*** Padrão 1
['1222222226', '16'] 

*** Padrão 2
['122', '12222', '1', '122222222', '1']
  • Mais: +

     Esse metacaractere define que o caractere antes de + pode ser repetido inúmeras vezes.

import re
msg='1227 122228 104 1222222226 1632323'

padrao1 = '12+6'
resposta = re.findall(padrao1, msg)
print("*** Padrão 1")
print(resposta, "\n")

padrao2 = '12+'
resposta = re.findall(padrao2, msg)
print("*** Padrão 2")
print(resposta, "\n")

     O primeiro padrão procura por substrings que começam com ‘1’, têm um ou mais caracteres ‘2’ e no final têm o caractere ‘6’. O segundo padrão começa com ‘1’ e é seguido por um ou mais caracteres ‘2’.

*** Padrão 1
['1222222226'] 

*** Padrão 2
['122', '12222', '122222222'] 
  • Chaves: { }

     Esse metacaractere define quantas vezes o caractere antes das chaves deve aparecer nos substrings.

import re
msg='1227 122228 104 1222222226 1632323'

padrao1 = '12{3}'
resposta = re.findall(padrao1, msg)
print("*** Padrão 1")
print(resposta, "\n")

padrao2 = '12{0,4}'
resposta = re.findall(padrao2, msg)
print("*** Padrão 2")
print(resposta, "\n")

padrao3 = '12{2,}'
resposta = re.findall(padrao3, msg)
print("*** Padrão 3")
print(resposta, "\n")

     O primeiro padrão procura por substrings que começam com o caractere ‘1’ e têm, em seguida, três caracteres ‘2’. O segundo padrão tem de zero a 4 caracteres ‘2’ após o primeiro caractere ‘1’. O terceiro padrão tem o caractere ‘1’ e dois ou mais caracteres ‘2’.

*** Padrão 1
['1222', '1222'] 

*** Padrão 2
['122', '12222', '1', '12222', '1'] 

*** Padrão 3
['122', '12222', '122222222']
  • Circunflexo: ^

     Esse metacaractere verifica se existe um determinado padrão no início de uma string.

import re
msg="E agora, José? A festa acabou, a luz apagou, o povo sumiu, a noite esfriou" 

padrao1 = '^E agora'
resposta = re.findall(padrao1, msg)
print("*** Padrão 1")
print(resposta, "\n")

padrao2 = '^A festa acabou'
resposta = re.findall(padrao2, msg)
print("*** Padrão 2")
print(resposta, "\n")

     O primeiro padrão consiste na substring ‘E agora’, enquanto o segundo padrão consiste na substring ‘A festa acabou’. O primeiro padrão é encontrado nos primeiros caracteres do alvo. O segundo padrão não é encontrado no início do alvo.

*** Padrão 1
['E agora'] 

*** Padrão 2
[] 
  • Cifrão: $

     Esse metacaractere verifica a existência de um determinado padrão no final de uma linha.

import re
msg="E agora, José? A festa acabou, a luz apagou, o povo sumiu, a noite esfriou"

padrao1 = 'esfriou$'
resposta = re.findall(padrao1, msg)
print("*** Padrão 1")
print(resposta, "\n")

padrao2 = '.{15}$'
resposta = re.findall(padrao2, msg)
print("*** Padrão 2")
print(resposta, "\n")

     O primeiro padrão verifica se a substring ‘esfriou’ é encontrada no final da linha. O segundo padrão verifica os últimos 15 caracteres da linha.

*** Padrão 1
['esfriou'] 

*** Padrão 2
['a noite esfriou']
  • Borda de palavra: \b

     Esse metacaractere define o início ou um fim de uma palavra.

import re
msg='arma, armação, armadilha'

resposta = re.findall(r"\barma", msg)
print("*** Padrão 1")
print(resposta, "\n")

resposta = re.findall(r"arma\b", msg)
print("*** Padrão 2")
print(resposta, "\n")

     O primeiro padrão procura pelo substring ‘arma’ no início das palavras e acha três palavras. O segundo padrão procura por ‘arma’ no final das palavras e só encontra uma palavra. Note que o caractere “r” é colocado no início da definição dos padrões. Isto indica para o Python não interpretar “\b” como backspace. Assim “\b” é considerada uma substring de dois caracteres contendo um caractere “\” e um caractere “b”. O caractere “r”, neste caso, corresponde à notação de string crua (raw).

*** Padrão 1
['arma', 'arma', 'arma'] 

*** Padrão 2
['arma']

     O uso de “\B” no padrão significa que a substring não é uma borda de palavra. Assim, para verificar que “rma” não está no início de uma palavra, basta usar

resposta = re.findall(r"\Brma", msg)
print(resposta, "\n")
  • Escape: \

     O Escape tira o poder de um metacaractere.

import re
msg="Em uma lista, \n todo mundo é normal: *?.\}"

resposta = re.findall(", \n", msg)
print("*** Padrão 1")
print(resposta, "\n")

resposta = re.findall("[\*\.]", msg)
print("*** Padrão 2")
print(resposta, "\n")

     O primeiro padrão procura por “\n” (quebra de linha), ou seja, procura por dois caracteres “\” e “n”. Neste caso, o primeiro caractere não é interpretado como escape (não existe definição de sequência especial “\n”). O segundo padrão procura pelo asterisco e pelo ponto e “\” é o metacaractere escape, pois existem os metacaracteres asterisco e ponto.

*** Padrão 1
[', \n'] 

*** Padrão 2
['*', '.'] 
  • Ou: |

     Esse metacaractere corresponde ao operador lógico OU.

import re
msg="Em uma lista, \n todo mundo é normal: *?.\}"

resposta = re.findall("lista|normal|\*", msg)
print(resposta, "\n")

     O padrão procura por “lista”, “normal” ou asterisco.

['lista', 'normal', '*']
  • Grupo: ( )

     Esse metacaractere serve para agrupar as expressões contidas dentro deles. Dessa forma, é possível repetir o conteúdo de um grupo com um qualificador de repetição como , +, ? e { }. No exemplo abaixo, o padrão procura por uma palavra que tenha hífen, antes e depois do hífen pode existir qualquer número de letras (minúsculas e maiúsculas)

import re
msg='''Sistemas de informação são descritos em termos de suas
dimensões tecnológica, organizacional e humana, o que exige uma
abordagem multidisciplinar. Nosso curso BSI-UNIRIO propicia uma
formação básica sólida em Sistemas de Informação, Ciência da
Computação e Matemática, além de propiciar formação com ênfase no
estudo das tecnologias, das organizações e de fatores humanos.'''

padrao = re.compile(r'([a-z]+)-([a-z]+)', re.IGNORECASE)
resposta = re.search(padrao, msg)

print("*** Informação sobre o objeto 'resposta'")
print(resposta, "\n")
print("*** Todo o string encontrado")
print(resposta.group(0), "\n")
print("*** Parte do string antes de '-'")
print(resposta.group(1), "\n")
print("*** Parte do string depois de '-'")
print(resposta.group(2), "\n")

A resposta é

*** Todo o string encontrado
BSI-UNIRIO 

*** Parte do string antes de '-'
BSI 

*** Parte do string depois de '-'
UNIRIO 
  • Retrovisor: \1

     Esse metacaractere armazena os grupos de dados encontrados de acordo com o padrão informado. No máximo podem ser definidos 9 grupos de dados (contados da esquerda para direita). No exemplo abaixo, o padrão é composto por dois grupos separados por um hífen. O primeiro grupo é representado por \1 e o segundo grupo por \2. O método sub() é usado para alterar msg.

import re
msg = 'Cursos: BSI-CCET, História-CCH, Medicina-CCBS'  
resposta = re.findall(r'([A-Za-zÀ-ü]+)-([A-Za-zÀ-ü]+)', msg)
print(re.sub(r'([A-Za-zÀ-ü]+)-([A-Za-zÀ-ü]+)', r'\1 - Graduação', msg), "\n")
print(re.sub(r'([A-Za-zÀ-ü]+)-([A-Za-zÀ-ü]+)', r'\2 - Unidade gestora', msg), "\n")

     A resposta é

Cursos: BSI - Graduação, História - Graduação, Medicina - Graduação 

Cursos: CCET - Unidade gestora, CCH - Unidade gestora, CCBS - Unidade gestora

Observações

Primeira observação: As sequências especiais consistem em ‘\’ e um caractere. Se o caractere não for um dígito ASCII ou uma letra ASCII, o resultado corresponderá ao segundo caractere. Por exemplo, \$ corresponde ao caractere ‘$’. Na seção acima, foram discutidas algumas sequências especiais. Outras sequências podem ser vistas abaixo.

  • \A – corresponde ao início do string;
  • \d – corresponde ao dígito decimal (classe [0-9]);
  • \D – corresponde ao não dígito (classe [^0-9]);
  • \S – corresponde a qualquer caractere que não seja um caractere de espaço em branco;
  • \w – corresponde ao caractere alfanumérico (classe [azA-Z0-9_]);
  • \W – corresponde a qualquer caractere não alfanumérico ([^a-zA-Z0-9_]);
  • \Z – corresponde ao final do string.

Segunda observação: A tabela abaixo mostra os metacaracteres chamados universais.

MetacaractereEspecificaçãoSignificado
.PontoQualquer caractere
*AsteriscoQualquer quantidade
.*Ponto e asteriscoQualquer coisa