sábado, 3 de janeiro de 2015

Gostaria de dedicar este para falar de uma ferramenta muito importante dentro de analytics: as expressões regulares (Regex na abreviação em inglês). Elas são muito úteis para procura e substituição de textos, segmentação de dados e para o desenvolvimento de robôs que façam uma leitura dos códigos em HTML de páginas da internet. Exemplificando um pouco mais essas aplicações, podemos encontrar padrões de texto para buscar ou validar datas, números de IPs, endereços de e-mail ou de internet, dados entre tags, padrão de documentos. São tantas aplicações que dificulta até mesmo sua organização em uma lista ou tabela, sendo mais útil tratar cada necessidade de acordo com a demanda.

Por definição, uma expressão regular é uma composição de símbolos com funções especiais que, agrupados entre si e com os caracteres de interesse, forma uma expressão. Esta é interpretada como uma regra, que indicará um resultado de sucesso se a entrada de dados casar com essa regra. De modo mais simples é um método formal para se especificar um padrão de texto. Assim, uma expressão regular descreve um conjunto de cadeias de caracteres, mas sem necessariamente listar todos os elementos do conjunto de texto que desejamos analisar.

Toda esta engenheira é realizada por uma gramática especial e pela chamada álgebra de conjuntos regulares, desenvolvida no trabalho do matemático estadunidense Stephen Cole Kleene (por isso pode ser chamada também de álgebra de Kleene). Como este é um blog de aplicações, não vamos nos aprofundar neste contexto, mas mencionamos para que você pudesse entender a origem e recomendamos seu estudo como forma de aperfeiçoamento desta técnica.

As expressões regulares são suportadas em praticamente todas as linguagens de programação, de bancos de dados ou não. Claro que no Python e no MongoDB não seria diferente. Neste post, dedicaremos atenção especial para o módulo re, do Python.


O Módulo re

O módulo re é usado para suprir a ausência de uma sintaxe literal para expressões regulares em Python. Faça a importação do módulo com o comando 

 >> import re   

Para começar, consideremos a string abaixo: 

 >>string = ‘Aplicacoes de text mining versão 1’   

No primeiro exemplo, vamos utilizar a função match para encontrar todas as palavras que estão antes da palavra ‘text’ na variável string. A sintaxe para esta busca é 

re.match(expressão_regular, string) 

 >> print re.match(r’(.*) text’, string)   
 <_sre.SRE_Match object at 0x01DD9960>   

Vemos que o retorno do nosso comando é um objeto. Para visualizar o conteúdo, utilizaremos o método group(). 

 >> print re.match(r’(.*) text’, string).group()   
 Aplicacoes de text   

Agora sim tivemos nosso retorno. Entretanto, repare que o que queríamos era buscar todas as palavras antes da palavra ‘text’, ou seja, queríamos apenas que o retorno fosse ‘Aplicacoes de’. Para alcançar este nosso primeiro objetivo, passamos o algarismo 1 como parâmetro do método group(). Assim, 

 >> print re.match(r’(.*) text’, string).group(1)   
 Aplicacoes de  

Que era o nosso resultado esperado. Ou seja, group() retornará tudo incluindo a palavra e group(1) retornará tudo até a palavra limite. 

Mas não se preocupe! Ainda também não explicamos o que significa o parâmetro r’(.*) text’ que utilizamos na função. Esta simbologia é o que podemos chamar de “coração das expressões regulares” ou, utilizando a nomenclatura correta, são os padrões das expressões regulares. Os caracteres r’ formam o prefixo da string, indicando que vamos buscar um texto “cru”. O . procura por qualquer tipo de caractere, com exceção de uma nova linha (\n), enquanto o * faz com que a regex encontre todos os caracteres existentes até o limitador. Ou seja, caso nosso parâmetro fosse lo*p, a regex retornaria lop, loop, looop e assim por diante até quando fosse necessário. 

Vamos procurar por uma palavra específica dentro de nossa string. Como exemplo, comecemos pela palavra ‘Aplicacoes’: 

 >>string = ‘Aplicacoes de text mining versão 1’   
 >> print re.match(r’Aplicacoes’, string).group()   
 Aplicacoes   

Tudo certo até aqui. Tentemos agora procurar a palavra ‘text’: 

 >> print re.match(r’text’, string).group()   

Não funcionou! Apareceu um erro do tipo ‘NoneType’ object has no attribute ‘group’. Isto porque a função match() retorna apenas o que há no começo da string quando queremos buscar palavras específicas. Assim, termos que utilizar a função search() para completar esta tarefa: 

 >> print re.search(r’text’, string).group()   
 text   

Tudo ok! A função search() funciona com a mesma sintaxe. A diferença é que podemos procurar o padrão dentro de qualquer posição do texto. Utilizando esta funcionalidade, vamos explorar os padrões que podem existir dentro de um campo que receba um endereço de e-mail. Por padrão, os endereços eletrônicos possuem o formato username@host. As três motivações para se trabalhar com expressões regulares neste caso são identificar o e-mail inteiro, apenas o username ou apenas o host. O próximo exemplo mostra como utilizar a função group() para cada uma destas aplicações. 

 >> email = ‘Nosso e-mail e leandro.guerra@artedosdados.com.br’   
 >> print re.search(‘([\w.-]+)@([\w.-]+)’, email).group() #retorna o e-mail inteiro   
 leandro.guerra@artedosdados.com.br   
 >> print re.search(‘([\w.-]+)@([\w.-]+)’, email).group(1) #retorna o username   
 leandro.guerra   
 >> print re.search(‘([\w.-]+)@([\w.-]+)’, email).group(2) #retorna o host   
 artedosdados.com.br   

Vamos detalhar agora o padrão que utilizamos. Como parâmetro passamos o padrão ([\w.-]+)@([\w.-]+). Repare que ele se assemelha com um formato de e-mail, pois temos ([\w.-]+) antes e após o símbolo @. Ou seja, o que realmente nos importa é entender o ([\w.-]+). Começamos com os parêntesis () apenas para estabelecer a lógica de que vamos procurar um grupo de coisas antes (e depois) do @. Os colchetes [] server para delimitar que queremos um conjunto de caracteres. Eles sozinhos não são suficientes, por isso adicionamos \w para indicar que queremos qualquer caractere presente no conjunto [a-zA-Z0-9_], pois e-mails não aceitam caracteres especiais. Entretanto, aceitam o ponto “.” ou o hífen “-“, sendo esta a razão de adicionarmos .- após o \w. Por fim, o sinal de + serve para dizer que queremos todas as repetições que houverem no padrão, e não apenas um dos caracteres.

Um abraço e até o próximo post!


0 comentários:

Postar um comentário