No artigo anterior introduzimos alguns conceitos básicos e descrevemos os principais padrões de regex. Neste artigo vamos mostrar mais alguns padrões e técnicas de regex, além de aplicações práticas do uso em data science.
Flags:
As flags são argumentos que podem especificar certos ajustes na hora de fazer a procura na string. A mais utilizada é a flag re.IGNORECASE que faz o padrão não diferenciar letras maiúsculas das minúsculas. Uma lista de todas as flags pode ser encontrada na documentação do módulo re. Para utilizar estas flag basta acrescentar um argumento flags com a primeira letra da flag na função regex:
df.column.str.contains(padrão, flags=re.I)
Ex: Queremos achar a palavra data science.
>>> serie = pd.Series([‘Data Science é a melhor área’,
>>> ‘Eu trabalho com Data Science’,
>>> ‘Data science é divertido de se trabalhar’,
>>> ‘eu fiz um curso em data science’,
>>> ‘data-science está em alta’,
‘DATA SCIENCE’])
>>> padrao = r’data[- ]science’
>>> mask = serie.str.contains(padrao, re.I)
>>> print(mask)
0 True
1 True
2 True
3 True
4 True
5 True
dtype: bool
Dessa forma o código se torna muito mais legível.
Âncora word boundary:
Um ponto de atenção é sobre a captura da string específica no meio de palavras que não desejamos capturar. Para esse tipo de problema existe um padrão específico conhecido como word boundary (e tem sua sintaxe representada por b que ajuda a capturar apenas a string desejada.
Ex: Por alguma razão obscura desejamos capturar somente a palavra dent.
>>> p = r’bdentb’
>>> serie = pd.Series([‘Dentista’, ‘dentadura’,
>>> ‘Oral Dent’, ‘Super Dent. Odonto’,
>>> ‘dentição’, ‘orto dent’,
>>> ‘Gente DENTE’, ‘Ultra dent’,
>>> ‘Ortodentistas’])
>>> serie.str.contains(p, flags=re.I)
0 False
1 False
2 True
3 True
4 False
5 True
6 False
7 True
8 False
dtype: bool
Lookarounds
Quando se quer garantir que algum outro padrão ocorre antes ou depois do padrão que se quer capturar, utiliza-se uma sintaxe especial de regex conhecida como lookarounds.
Os padrões dentro dos lookarounds não serão capturados. Apenas garantem a ocorrência antes ou depois de um padrão.
Existem 2 principais tipos de lookarounds, os lookaheads que verificam a ocorrência de um padrão à frente, e os lookbehind que garantem a ocorrência de a padrão antes. Cada um destes se dividem em mais dois: os positivos que só capturam a string se o padrão existir, e os negativos que só capturam o padrão se o padrão não existir.

Ex: Queremos pegar somente as os elementos da série que contenham a palavra data quando não for seguida de science.
>>> p = r’data(?![ -]science)’
>>> serie = pd.Series([‘Qual é a data do seu aniversário?’,
>>> ‘Eu trabalho com data science’,
>>> ‘A data da prova foi remarcada’,
>>> ‘Data-Science’,
>>> ‘É a melhor data’
>>> ])
>>> serie.str.contains(p, flags=re.I)
0 True
1 False
2 True
3 False
4 True
dtype: bool
Método extract do pandas
Quando se trabalha com data science existem algumas possibilidades de extração de uma parte específica de uma string contida em uma coluna de um dataframe.
A biblioteca pandas possui um método chamado str.extract que faz exatamente isso. O método captura cada grupo que estiver entre ()( parênteses) e retorna um dataframe onde cada coluna é um grupo de captura.
Ex: Queremos extrair somente o domínio de uma série de URLs.
>>> sites = pd.Series([
>>> ‘https://datarisk.io/sobre/’,
>>> ‘https://medium.com/datarisk-io’,
>>> ‘https://stackoverflow.com/’,
>>> ‘https://www.youtube.com/’,
>>> ‘https://github.com/’
>>> ])
>>> p = r’https?://([w.-]+)’
>>> dominios = sites.str.extract(p, flags=re.I)
>>> print(dominios)
0
0 datarisk.io
1 medium.com
2 stackoverflow.com
3 www.youtube.com
4 github.com
Apesar de conseguir capturar os grupos com êxito, ainda podemos melhorar o resultado.
Existe uma maneira de nomear cada grupo tornando ele um named group. Basta colocar um ?P<nome_do_grupo> no começo do parênteses de forma que o grupo acima fique (?P<dominio>[w.-]+), no caso do grupo ter o nome de domínio.
Assim o exemplo acima ficaria da seguinte maneira:
>>> sites = pd.Series([
>>> ‘https://datarisk.io/sobre/’,
>>> ‘https://medium.com/datarisk-io’,
>>> ‘https://stackoverflow.com/’,
>>> ‘https://www.youtube.com/’,
>>> ‘https://github.com/’
>>> ])
>>> p = r’https?://(?P<dominio>[w.-]+)’
>>> dominios = sites.str.extract(p, flags=re.I)
>>> print(dominios)
dominio
0 datarisk.io
1 medium.com
2 stackoverflow.com
3 www.youtube.com
4 github.com
Back References
Algumas vezes é necessário que uma string que se encaixa em um certo padrão ocorra repetidas vezes. O regex possui uma forma de resolver exatamente esse problema com o que são chamados as back references que repetem um grupo de captura. A sintaxe para isso é <número do grupo que se quer referenciar>
Ex: Queremos extrair somente sequências de números que contenham números que se repetem de 4 a mais vezes e que não sejam zeros:
>>> numeros = pd.Series([
>>> ‘123456’,
>>> ‘11116’,
>>> ‘1110088’,
>>> ‘7897426’
>>> ‘6471264777777999’,
>>> ‘1010101010’
>>> ])
>>> p = r’([1–9])1{3,}’
>>> numeros.str.contains(p, flags=re.I)
0 False
1 True
2 False
3 True
4 False
dtype: bool
Se houvessem mais grupos eles teriam que ser referenciados por 2, 3 … e assim por diante em ordem de aparição.
Conclusão
Esta segunda parte do artigo mostrou mais alguns padrões básicos que juntos com os da primeira parte conseguem solucionar 90% dos problemas que envolvem strings.
Ainda há algumas funções do módulo re, que você pode pesquisar por conta própria e que não foram abordados. Também existem alguns padrões mais exotéricos, mas acredito que o conteúdo destes dois artigos e algum tempo de prática já te ajudam a resolver qualquer problema de processamento de strings.
Espero que tenham gostado e até o próximo artigo!
Referências
2. rexegg — Site de referência ótimo para regex
4. Regexr Site que permite a construção de pattern com explicação e highlights
[Rr]eg(ular)?s?[Ee]x(pressions)?
PARTE 1: https://medium.com/datarisk-io/rr-eg-ular-s-ee-x-pressions-segunda-parte-2-dois-cec5a510ea8d

Cientista de dados