Não estou com tempo pra criar um PR agora, mas seguem algumas sugestões.
Para limpar a string, em vez de ter uma lista do que quer remover, é mais simples filtrar pelo que quer manter, já que é uma lista bem menor (apenas os dígitos de 0 a 9).
Ou seja,
import string
def __clear(string_chain: str) -> str:
return ''.join(c for c in string_chain if c in string.digits)
Na verdade é questionável se uma string como "abc123xxx456,;.^789{$#@}09"
deveria ser considerada um CPF (afinal, estamos limpando todos os caracteres indesejados e verificando os números que sobraram). Talvez ele só devesse aceitar no máximo os separadores (ponto e hífen) em posições específicas, mas enfim...
Se bem que, como vc usa isso para fazer o cálculo dos dígitos verificadores, talvez seja mais simples já converter tudo para int
, em vez de criar outra string.
E o cálculo pode ser feito mais diretamente, não precisa separar em tantos métodos. E até o uso de reduce
eu acho desnecessário, pois um loop simples é mais que suficiente.
Fiz uma versão mais simplificada, mas que pode ser adaptada no seu código:
import string
def extrai_digitos(string_chain):
return list(int(c) for c in string_chain if c in string.digits)
def calcula_digito(multiplicador, digitos):
total = 0
for d in digitos:
if multiplicador >= 2:
total += d * multiplicador
multiplicador -= 1
else: break
resto = total % 11
if resto < 2:
return 0
else:
return 11 - resto
def validar_cpf(cpf):
digitos = extrai_digitos(cpf)
if len(digitos) != 11:
return False
if digitos[9] != calcula_digito(10, digitos):
return False
if digitos[10] != calcula_digito(11, digitos):
return False
return True
string_chain = '123@#$%456&*()789-09'
print(validar_cpf(string_chain))
Ah, também dá pra calcular ambos os dígitos verificadores em um único loop:
import string
def extrai_digitos(string_chain):
return list(int(c) for c in string_chain if c in string.digits)
def calcula_resto(resto):
if resto < 2:
return 0
return 11 - resto
def validar_cpf(cpf):
digitos = extrai_digitos(cpf)
if len(digitos) != 11:
return False
total1 = total2 = 0
multiplicador = 11
for d in digitos:
if multiplicador >= 2:
if multiplicador >= 3:
total1 += d * (multiplicador - 1)
total2 += d * multiplicador
multiplicador -= 1
else: break
return digitos[9] == calcula_resto(total1 % 11) and digitos[10] == calcula_resto(total2 % 11)
string_chain = '123@#$%456&*()789-09'
print(validar_cpf(string_chain))
Algoritmos adaptados daqui e daqui.