Solucionado (ver solução)
Solucionado
(ver solução)
4
respostas

Como retornar uma resposta quando a validação é incorreta? Validação de número de celular.

Olá pessoal!

Tudo bem?

Baseado na aula, comecei a criar uma classe para validar um número de celular (formato brasileiro), mas não estou conseguindo concluir o código para que se ele tiver um número inválido ele possa me retornar uma frase, como por exemplo "Inválido".

Deduzo que não estou conseguindo prosseguir, porque não entendi o que de fato ele está me retornando quando retorna False, no valida_celular do _ init _.

  • Tentei fazer: um print('Número inválido'), mas não tem muito sentido, porque ele acaba passando pelo _ str _ e já dá o primeiro erro e depois entra no formata_numero.

Deveria criar uma função que pudesse tratar esse False ?

Possivelmente é apenas lógica, mas fiquei travado nesse problema.

Vocês poderiam me auxiliar a entender melhor e destravar esse problema?

Segue classe:

import re

class CelularBr():
    """
    Esta classe irá validar o número de celular, retornando-o
    no formato padrão do Brasil: (xx) xxxxx-xxxx.

    Caso o número não seja válido, retornará a mensagem:
    "Número inválido"
    """
    def __init__(self, celular):
        celular = str(celular)
        if self.valida_celular(celular):
            self.celular = celular
        else:
            raise ValueError('Número inválido') 


    def __str__(self):
        return self.formata_numero()

    def valida_celular(self, celular):
        """
        Esta função irá validar (com Regex) o número de celular
        com o DDD.
        Retornando True ou False.
        """
        padrao = '[1-9]{2}9[5-9]{1}[0-9]{7}'
        primeira_validacao = re.findall(padrao, celular)
        if primeira_validacao:
            segundo_padrao = '0{6}|1{6}|2{6}|3{6}|4{6}|5{6}|6{6}|7{6}|8{6}|9{6}'
            segunda_validacao = re.findall(segundo_padrao, primeira_validacao[0])
            if segunda_validacao:
                return False 
            else:
                return True
        else:
            return False

    def formata_numero(self):
        """
        Esta função retornará o o número formatado no padrão:
        (xx) xxxxx-xxxx.
        """
        padrao = '([1-9]{2})(9[0-9]{4})([0-9]{4})'
        resposta = re.search(padrao,self.celular)

        ddd = resposta.group(1)
        primeiros_digitos = resposta.group(2)
        ultimos_digitos = resposta.group(3)
        numero_formatado = (f"({ddd}) {primeiros_digitos}-{ultimos_digitos}")

        return numero_formatado

Segue main que estava testando:

from celularBr import CelularBr
import re

celular = 199916666669
#celular = 19991250339


celular_objeto = CelularBr(celular)

print(celular_objeto)
4 respostas

Olá Francisco, tudo bem com você?

Para que o código funcione efetuando a validação com o número proposto, será necessário invertermos o retorno da segunda validação. Como apresentado abaixo.

if segunda_validacao:
    return True
else:
    return False

Porém, vale ressaltar que a segunda validação impedirá que números “comuns” de celular sejam não validados. Abaixo, alguns exemplos de números que retornarão inválidos devido a segunda validação:

celular_1 = 34995734567
celular_2 = 35995753456
celular_3 = 31987653423

Qualquer dúvida fico à disposição.

Abraços e bons estudos.

Caso este post tenha lhe ajudado, por favor, marcar como solucionado ✓. Bons Estudos!

Oi Felipe!Obrigado pela resposta.

Fiz de propósito essa lógica de False e True.

A primeira validação seria para verificar se o número está de acordo com o padrão do celular. Não consegui uma Regex que pudesse em uma só, validar se esse número tinha elementos repetidos (como 111111,666666...) então criei uma segunda validação para verificar. Mas como se encontrar número repetido não é algo válido, quis que retornasse False, para que não entrasse na função de formatar número.

padrao = '[1-9]{2}9[5-9]{1}[0-9]{7}'                                                                                #Esse regex irá verificar se está no padrão do número de um celular
        primeira_validacao = re.findall(padrao, celular)                                                    
        if primeira_validacao:
            segundo_padrao = '0{6}|1{6}|2{6}|3{6}|4{6}|5{6}|6{6}|7{6}|8{6}|9{6}'  #Esse regex irá verificar se não foi preenchido com números repetidos
            segunda_validacao = re.findall(segundo_padrao, primeira_validacao[0])
            if segunda_validacao:
                return False                                                                                                     #Se encontrar, retorna False pq celular com muitos repetidos não é válido
            else:
                return True                                                                                                         
        else:
            return False

O que gostaria dessa classe é que se ela encontrasse um número inválido, me retornasse uma string: "Número inválido".

Para que quando verificasse isso em um DataFrame, ela passasse por todos os elementos e validasse e formatasse os números válidos e preenchesse a string de "Número inválido" onde fosse inválido.

Você poderia me auxiliar?

solução!

Oi Francisco,

Muito obrigado pelo retorno e por explicar com mais detalhes sobre o que gostaria de obter. Seguindo a proposta de trabalho apresentada, será necessário algumas mudanças na estrutura do código.

O método __init__ não é capaz de retornar uma string, esse método é capaz retornar apenas none ou, uma exceção, como você fez com o raise ValueError.

Sendo assim, alterei o método __init__ para apenas receber o número do celular e o transformar em uma string. Fora isso, criei um método auxiliar que retorna a formatação do número em caso válido, ou a string de número inválido. Como mostro abaixo:

class CelularBr:

    def __init__(self, celular):
        self.celular = str(celular)

    def verifica_validacao(self):
      if self.valida_celular(self.celular):
          return self.formata_numero()
      else:
          return "Número inválido" 

Os demais métodos permaneceram como o código original, logo após o método verifica_validacao.

Quanto ao teste no pandas, podemos utilizar o método apply para percorrermos a coluna de telefone e aplicarmos a função verifica_validacao, como mostro abaixo:

import pandas as pd
numeros = {
    'Nome': ['Ana', 'Julia', 'Pedro', 'Paulo', 'Rafael', 'Joana'],
    'Telefone': ['37975289327', '53976666661', '67986647586', '53977777708', '51966666608', '95976704635']
}
df = pd.DataFrame(numeros)

df['Validação'] = df["Telefone"].apply(lambda celular: CelularBr(celular).verifica_validacao())

print(df)

Resultado:

NomeNumeroValidação
0Ana37975289327(37) 97528-9327
1Julia53976666661Número inválido
2Pedro67986647586(67) 98664-7586
3Paulo53977777708Número inválido
4Rafael51966666608Número inválido
5Joana95976704635(95) 97670-4635

Deixo abaixo o código completo para a comparação.

import re
import pandas as pd


class CelularBr:

    def __init__(self, celular):
        self.celular = str(celular)

    def verifica_validacao(self):
        if self.valida_celular(self.celular):
            return self.formata_numero()
        else:
            return "Número inválido"

    def valida_celular(self, celular):
        padrao = '[1-9]{2}9[5-9]{1}[0-9]{7}'
        primeira_validacao = re.findall(padrao, celular)
        if primeira_validacao:
            segundo_padrao = '0{6}|1{6}|2{6}|3{6}|4{6}|5{6}|6{6}|7{6}|8{6}|9{6}'
            segunda_validacao = re.findall(segundo_padrao,
                                           primeira_validacao[0])
            if segunda_validacao:
                return False
            else:
                return True
        else:
            return False

    def formata_numero(self):
        padrao = '([1-9]{2})(9[0-9]{4})([0-9]{4})'
        resposta = re.search(padrao, self.celular)

        ddd = resposta.group(1)
        primeiros_digitos = resposta.group(2)
        ultimos_digitos = resposta.group(3)
        numero_formatado = (f"({ddd}) {primeiros_digitos}-{ultimos_digitos}")

        return numero_formatado

numeros = {
    'Nome': ['Ana', 'Julia', 'Pedro', 'Paulo', 'Rafael', 'Joana'],
    'Telefone': ['37975289327', '53976666661', '67986647586', '53977777708', '51966666608', '95976704635']
}
df = pd.DataFrame(numeros)

df['Validação'] = df["Telefone"].apply(lambda celular: CelularBr(celular).verifica_validacao())

print(df)

Fico à disposição.

Abraços.

Oi Felippe!!

Nossa, eu quem agradeço demais pela ajuda. Baita resposta completa com testes nos dados e tudo mais.

Perfeito!! :D

Valeu demais \0/ \0/

A princípio tinha pensado em fazer "list comprehension": [CelularBr(numero).verifica_validacao() for numero in biblioteca['TELEFONE']]

Mas vi que utilizou o Apply.

Vi esse texto: https://towardsdatascience.com/how-to-make-your-pandas-operation-100x-faster-81ebcd09265c

E tirei a prova:

inicio = time.time()
[CelularBr(numero).verifica_validacao() for numero in biblioteca['TELEFONE']]
fim = time.time()
print(fim - inicio)

0.0429384708404541

inicio = time.time()
biblioteca['TELEFONE'].apply(lambda celular: CelularBr(celular).verifica_validacao())
fim = time.time()
print(fim - inicio)

0.013110876083374023

Resultado: Apply 3.5x mais rápido.

Abração e obrigado mais uma vez!!!