Mandar um café pro programador

Pode me ajudar a transformar cafeína em código?

Tutorial Expressões Regulares em Python, parte 1

Neste tutorial de Python, de nossa seção de Strings, daremos nossa aula mais importante: sobre expressões regulares. Veremos o que é, para que servem, como são usadas e como usá-las.

Baixe a apostila Python Progressivo
Certificado do curso (para trabalhar como programador profissional)

Expressão Regular: O que é? Para que serve ?


Vamos supor que você baixou um site inteiro da internet, e vai tratar de milhões e milhões de linha de texto nele, em busca de algo específico: números de telefone.

Não tem como da rum control+F ou usar métodos para buscar substrings, por um detalhe importante: você não sabe que números são esses.

Mas você sabe de uma coisa: começam por parêntesis, tem dois dígitos (o DDD), fecha parêntesis, tem um 9, depois mais quatro dígitos, as vezes um hífen as vezes não, e mais quatro números.

E é aí que as expressões regulares vão atuar: você vai definir um padrão e elas vão buscar no texto esse padrão. No parágrafo anterior acabamos de criar um padrão para achar números de telefone.
É uma expressão regular, no caso, ainda em nossa cabeça, já já vamos transformar ela em código Python.

Agora e-mail, vamos supor que queira 'caçar' e-mail na grande rede para fazer propaganda de sua empresa. Os endereços de e-mail tem o seguinte formato:
  1. algum texto
  2. @
  3. algum site
  4. .com em algum lugar (como gmail.com ou bol.com.br, mas tem '.com')



Pronto, criamos um padrão. Com isso, podemos criar uma expressão regular para tratar um texto gigante, que vai nos retornar os endereços de e-mail!

As regular expressions (também conhecidas pela abreviação Regex) são isso: padrão de um texto que vamos procurar.

Trabalhando sem expressão regular

Primeiro, vamos resolver um problema sem expressão regular, para você entender o que é criar um padrão para detectar algo.
"Crie uma função que recebe um argumento do tipo string, e diz se ela representa um telefone do tipo xxxx-yyyy ou não".

De cara, nossa string tem que ter tamanho 9. Usamos a função len() pra isso. Se não tiver, já retorna falso, não tá do jeito que a gente quer.

Depois, os caracteres das 4 primeiras posições.
Eles devem ser números, ou seja, vamos usar a função isdecimal() para definir se são ou não.

Já o quinto caractere, de índice 4, deve ser o hífen '-'.
Se não for, mostramos mensagem de erro.

Por fim, testamos novamente se os 4 últimos são números.



Nosso código fica assim:

def eTelefone(numero):
 if len(numero) != 9:
  print("Tamanho diferente de 9")
  return False

 for index in range(0,4):
  if numero[index].isdecimal() is not True:
   print("4 primeiros nao sao numero")
   return False
 if numero[4] != '-':
  print("Nao tem hífen")
  return False
 
 for index in range(5,9):
  if numero[index].isdecimal() is not True:
   print("4 ultimos nao sao numero")
   return False

 return True
 
while True:
 numero = input("Numero no formato 'xxxx-yyyy': " )
 
 if eTelefone(numero) is True:
  print("Válido")
 else:
  print("Inválido")

Experimente!
Teste:
1234-6789
12345678
1234 5678

Bacana, não ?

Mas isso só funciona se você digitar apenas um número, e se digitar:
"Fala galera, meu numero é 1234-5678"

Não detecta!

Aí é simples, temos que analisar blocos de 9 caracteres, 9 em 9.
Fazemos isso assim: pedaco[i:i+9]

Onde i varia de 0 até o tamanho da string, só pra garantir que vamos percorrer todos os blocos possíveis de 9 caracteres.

Veja como fica nosso código que detecta qualquer número nessas condições, numa string qualquer:

def eTelefone(numero):
 if len(numero) != 9:
  return False
 for index in range(0,4):
  if numero[index].isdecimal() is not True:
   return False  
 if numero[4] != '-':
  return False
 for index in range(5,9):
  if numero[index].isdecimal() is not True:
   return False
 print("Numero detectado: ", numero)
 return True
 
while True:
 numero = input("Numero no formato 'xxxx-yyyy': " )
 
 for i in range( len(numero)):
  pedaco=numero[i:i+9]
  eTelefone(pedaco)


Veja o resultado de alguns testes:

Expressão Regular em Python

Usando Expressão Regular

O código anterior é bacaninha, mas tem vários problemas:
  • É longo
  • Se alguém digitar xxxx-yyyy, xxxxyyyy, ou (xx) yyyyzzzz ou xx yyyy-zzzz etc etc, dará erro, e na verdade são números válidos de telefone
  • Se eu repetir: xxxx-yyyy xxxx-yyyy varias vezes, vai detectar e repetir várias vezes




E por aí vai, de problemas.
É aí que entra em ação nossas regexes.

Regex de dígito: \d
A expressão regular mais simples é o padrão \d
Ele representa um simples dígito. Apenas isso.

Qualquer numeral de 0 até 9, é detectado via '\d'

Logo uma regex que detecta nosso número de telefone é:
\d\d\d\d-\d\d\d\d

Se colocarmos um valor entre chaves, dizemos que aquela regex deve 'bater' aquele número de vezes.
Note que repetimos \d quatro vezes, um hífen e mais quatro vezes repetimos \d.

Podemos simplificar para: \d{4}-\d{4}
Bem mais simples, não ?

E com DDD ? As expressões abaixo funcionariam
\d{2} \d{4}-\d{4}   :bate com xx yyyy-zzzz
(\d{2}) \d{4}-\d{4}: bate com (xx) yyyy-zzzz
(\d{2}) \d{8} : bate com xx yyyyzzzz

Tá sentindo a alma do negócio?

O Módulo re

O Python tem uma coleção de funções para tratarmos e lidarmos com regex, estão todas no módulo re.

Ou seja, faça sempre a importação:
  • import re

Objetos Regex e função recompile

A função recompile() do módulo re recebe uma string com sua regex e retorna um objeto do tipo Regex.

Vamos passar uma expressão regular para a função recompile e armazenar o retorno na variável minhaRegex:
  • minhaRegex = re.compile(r'\d{4}-\d{4}')


Pessoal, \d representa qualquer caractere que é um dígito.
Diferente do \n que representa uma única coisa, \d são duas coisas: uma barra e um d

Usamos a letra r antes da string no método compile para não precisar fazer:
  • minhaRegex = re.compile('\\d{4}-\\d{4}')

Lembre-se: para representar uma barra \ em uma string, temos que escapar ela com outra barra: \\
Usando o r, podemos escrever diretamente sem precisa escapar.

Métodos search e group dos Objetos Regex

Agora temos uma variável do tipo Regex, em minhaRegex.

Esses objetos tem um método chamado search(), que vai receber uma string e pesquisar nela toda e qualquer correspondência da regex que você criou.
Se não achar, ela retorna None.

Vamos armazenar a string que o usuário vai digitar em texto e guardar as correspondências que bateram na variável resultado:
  • resultado = minhaRegex.search(texto)

O método search retorna um objeto do tipo Match (algo como 'bater', no sentido de combinou, deu certo...deu match no Instagram). Ou seja, a variável resultado é um objeto do tipo Match.

Objetos do tipo Match tem um método chamado group(), que armazena todas as correspondências da regex encontradas na string.

O código, com expressão regular, que acha um número agora é:

import re
while True:
 texto = input("Numero no formato 'xxxx-yyyy': " )
 
 minhaRegex = re.compile(r'\d{4}-\d{4}')
 resultado = minhaRegex.search(texto)
 
 print(resultado.group())

Achar todas ocorrências: findall

No código anterior, tem um problema: só vai achar a primeira ocorrência que bater com a regex.
Para achar todas, usamos o método findall.

Ele recebe duas strings: o padrão da regex, e a string.
E simplesmente retorna uma lista com todas as ocorrências que batem.

Veja com fica o código que acha tudo:

import re

while True:
 texto = input("Numero no formato 'xxxx-yyyy': " )
 minhaRegex = re.findall(r'\d{4}-\d{4}', texto)

 print(minhaRegex)

Nenhum comentário:

Postar um comentário

Bora fazer evoluir o ensino da Programação no Brasil ?

Que tal apoiar e fazer crescer o ensino da programação no Brasil ?

Ajudar nosso país a crescer e se desenvolver cada vez mais, tecnologicamente?

Clica abaixo pra saber mais!

Apoiar o Projeto Progressivo