Após vermos um artigo introdutório de Regex em Python, vamos ao que interessa: As grandes façanhas que conseguimos fazer com essa ferramenta.

Everton Tomalok
6 min readOct 29, 2018

Antes de começarmos a ver suas utilidades avançadas, gostaria de introduzir mais algumas ferramentas de uma regex.

Recuperando agrupamentos de padrões nomeados em uma string

Podemos criar grupos de valores a serem extraídos, utilizando parenteses ().

a(bc)          os parenteses criam um grupo para capturar valores bc               a(?P<foo>bc)   usando ?P<foo> nós nomeamos nosso grupo de captura para foo

Por exemplo, podemos procurar por um grupo de captura, como fizemos no primeiro artigo, aonde gostaríamos de capturar (Gro)(ot).

Poderíamos então nomear esses grupos de capturas, como no exemplo abaixo, utilizando (?P<nome_variavel>pattern):

>> import re>> frase = "Eu sou o Groot">> # Nomeando os grupos de extração
>> pattern = r"(?P<primeiro>Gro)(?P<segundo>ot)"
>> # Vamos capturar grupos de caracteres 'Gro' e 'ot'
>> match = re.search(pattern, frase)>> # Recuperando o grupo de nome 'primeiro'
>> match.group('primeiro')
>> 'Gro'
>> >> # Recuperando o grupo de nome 'segundo'
>> match.group('segundo')
>> 'ot'

Sabendo desta técnica, podemos minerar em textos, em busca de datas, aonde podemos definir o padrão de captura.

Em nosso exemplo, iremos utilizar o padrão de datas dd/mm/aaaa.

Vamos ao exemplo:

>> import re>> frase = "Eu gostaria de viajar para o passado. Acho uma data boa para retornar, no dia 15/06/1999.">> pattern = r'(?P<dia>[0-9]{2})/(?P<mes>[0-9]{2})/(?P<ano>[0-9]{4})'>> match = re.search(pattern, frase)>> match.group('dia')
>> 15
>> match.group('mes')
>> 06
>> match.group('ano')
>> 1999

Encontrando frases em uma string

Com regex, conseguimos procurar por determinados padrões, dentro de uma string, e gerar “um looping” de buscas.

Por exemplo, desejo procurar pela palavra “brincar”, todas as vezes em que ela aparece em um string. O método .finditer(pattern, text), onde pattern passaremos o padrão de regex a ser buscada, e o texto, a string que deve ser scaneada; onde o retorno deste método é um um objeto iterável (que poder ser percorrido por um “for”).

Cada elemento encontrado dentro dessa string, terá alguns outros métodos possíveis. No momento, utilizaremos apenas o .start() para recuperar o começo da string, e o .end() para recuperarmos o index do ultimo carácter da frase procurada.

Vejamos o exemplo abaixo:

>> import re>> # Texto
>> text = "Uau, ele gosta mesmo de brincar com aquela outra criança. Mas brincar faz bem para saúde."
>> # Padrão
>> pattern = r'brincar'
>> # Buscando uma string e identificando sua localização
>> for match in re.finditer(pattern, text):
>> s = match.start()
>> e = match.end()
>> print('Encontrado "%s" com inicio em %de final em %d' % (text[s:e], s, e))
>> print("\n")
>> Encontrado "brincar" com inicio em 24 e final em 31
>> Encontrado "brincar" com inicio em 62 e final em 69

Substituindo substrings em um texto

Todos conhecemos o poder do Python, ao processarmos strings em Python, inclusive já citei o método .replace(). Com ‘re’, conseguimos fazer ainda mais.

Vamos começar no básico, substituindo uma frase estática de uma string, utilizando o método .sub(frase_a_ser_substituida, nova_frase, string):

>> import re>> # Substituir palavras
>> endereco = 'Avenida Paulista, 1500, São Paulo'
>> re.sub('Avenida', 'Av.', endereco)
>> 'Av. Paulista, 1500, São Paulo'

Porém, este método nos permite, ir muito além. Podemos inclusive, definir um um padrão, que contenha um certo número de letras, e substituir todas substrings que se encaixem a este padrão.

No exemplo, vamos substituir todas palavras, que contenham 5 caracteres, por outra substring de valor “alterado”.

Obs.: o \w é o metacaracter que indica todo carácter de valor alfa-numérico (“0 a 9” e de “a até z”).

>> import re>> frase = 'Eu gosto de torta '
>> re.sub(r'\w{5}', ' alterado ', frase)
>> "Eu alterado de alterado"

Utilizando regex para gerar tokens

Tokenização, em processamento de linguagem natural, é extrair de uma string, sentenças e todas as frases dentro de um texto.

Ex:

  • “Eu sou uma sentença. Esta é outra sentença!”
  • Palavras sentença 1 : “Eu” , “sou”, “uma”, “sentença”, “.”
  • Palavras sentença 2: “Esta”, “é”, “outra”, “sentença”, “!”

Como podemos ver, cada token representa uma palavra, onde cada uma tem seu significado sintático, como por exemplo “sou”, que representa um verbo.

Podemos ver também que sinais de pontuação como o ponto final e o sinal de exclamação, são considerados tokens.

Poderiamos utilizar o método .split() do Python para nos auxiliar a gerar tokens.

>> text = "Eu sou uma sentença. Esta é outra sentença!">> text.split()>> ['Eu', 'sou', 'uma', 'sentença.', 'Esta', 'é', 'outra', 'sentença!']

Muito bom, porém os sinais de pontuação não foram separados da palavra ‘sentença’, como na definição vista acima.

Utilizando Regex, utilizando o metacaracter \w+, indicamos um pattern de recuperação de conjuntos alfa-númericos, que tenham de pelo menos um carácter, ou seja, será quebrado nos espaços, e irá retornar todas as frases encontradas. Para recuperarmos todas as ocorrência, de uma única vez, utilizaremos o método .findall() do re, que irá nos retornar uma lista, com todas as ocorrências.

Vejamos o exemplo abaixo:

>> import re>> text = "Eu sou uma sentença. Esta é outra sentença!">> pattern = r'\w+'>> tokens = re.findall(pattern, text)>> ['Eu', 'sou', 'uma', 'sentença', 'Esta', 'é', 'outra', 'sentença']

A extração foi muito boa. Porém os sinais de pontuação foram eliminados, pois estes não são caracteres alfa-numéricos.

Em alguns casos, teremos de fazer análise léxica e morfológica, para entendermos o contexto em que este token está inserido, e os sinais de pontuação, podem nos ajudar nessa interpretação. Até mesmo para identificar sujeito e predicados, os sinais de pontuações podem nos ajudar.

Então, para preservamos os sinais de pontuação, teremos de adaptar nossa regex. Utilizaremos o sinal “|” pipe, que indica “ou”.

Após o metacaracter \w, iremos acrescentar a o sinal “ou” seguido de todas as pontuações que julgarmos necessárias, dentro do limitadores de alfabeto []. Utilizaremos também o sinal quantitativo “+”, para indicarmos que o sinal de pontuação deve ocorrer uma ou mais vezes, para que seja recuperado.

Nossa regex ficará assim:

pattern = r”\w+|[,.!?]+”

Traduzindo esse regex, ficará assim: “Recupere todos caracteres alfa-numéricos que ocorram mais de uma vez ou todos os sinais de pontuação delimitados no [] que ocorram mais de uma vez”

>> import re>> text = "Eu sou uma sentença. Esta é outra sentença!">> pattern = r"\w+|[,.!?]+">> re.findall(pattern, text)
>> ['Eu', 'sou', 'uma', 'sentença', '.', 'Esta', 'é', 'outra', 'sentença', '!']

Agora sim, nossos tokens foram corretamente separados!

Inclusive, nossa regex, é capaz de separar mais de um sinal de pontuação com mais de uma ocorrência seguida, por exemplo as reticências ‘… ‘ , como veremos abaixo:

>> import re>> text = "Olá... tudo bem?">> pattern = r"\w+|[,.!?]+">> re.findall(pattern, text)>> ['Olá', '...', 'tudo', 'bem', '?']

Quando comecei a estudar Processamento de Linguagem Natural (PLN), achei do car@lho vendo essas técnicas, de como podemos utilizar regex, para facilitar nosso trabalho, no pré processamento de textos.

E isso, é só o começo. Regex está fortemente ligada a PLN.

Podemos criar stemmers, que removem a palavra para seu radical; por exemplo gostar, gostando, gostei, o seu radical comum será ‘gost’, pois deste radical, podemos gerar todas suas outras combinações.

Além do Stem, temos outra técnica, conhecida como “Lematização”, que é através da conjugação verbal do token (caso seja etiquetado como um verbo), trazer esse token para o infinitivo. Utilizando o mesmo exemplo, gostar, gostando e gostei, o seu Lema será o ‘gostar’, a forma infinitiva do verbo.

Porém, pretendo mais a frente, falar com mais calma sobre esses dois temas, e dar uma explicação mais detalhada.

E por hoje, isso é tudo pessoal!

Novamente, me disponho a eventuais dúvidas!

Abraços!!!

--

--

Everton Tomalok

I’m a Data Scientist / Data Engineer and Python Developer, who loves math and to discover new technologies. In love with NLP and Computer vision.