Created
November 23, 2018 15:59
-
-
Save williaanlopes/826fde767567ea98aecf0a0208df1c3f to your computer and use it in GitHub Desktop.
Validando CPF com Haskell (Validating CPF with Haskell)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-- | |
Exemplo de CPF 546.471.429-49 | |
Tutorial no link: https://www.devmedia.com.br/validando-o-cpf-em-uma-aplicacao-java/22097 | |
--} | |
module Util.CpfValidator where | |
import Data.Char | |
{-- | |
Para calcular o 1º dígito verificador | |
Cada um dos nove primeiros números do CPF é multiplicado por um peso que começa | |
de 10 e que vai sendo diminuido de 1 a cada passo, somando-se as parcelas calculadas: | |
# sm = (5*10)+(4*9)+(6*8)+(4*7)+(7*6)+(1*5)+(4*4)+(2*3)+(9*2) = 249; | |
# Calcula-se o dígito através da seguinte expressão: | |
11 - (sm % 11) = 11 - (249 % 11) = 11 - 7 = 4 | |
--} | |
calculoPrimeiroDigitoVerificador :: String -> Int | |
calculoPrimeiroDigitoVerificador [] = 0 | |
calculoPrimeiroDigitoVerificador (x:xs) = varificaDigito ( 11 - ( mod (somatorioDigitoVerificador (x:xs) 10) 11 ) ) | |
calculoSegundoDigitoVerificador :: String -> Int | |
calculoSegundoDigitoVerificador [] = 0 | |
calculoSegundoDigitoVerificador (x:xs) = varificaDigito ( 11 - (mod (somatorioDigitoVerificador (x:xs) 11) 11) ) | |
{-- | |
Para calcular o 2º dígito verificador | |
Cada um dos dez primeiros números do CPF, considerando-se aqui o primeiro DV, | |
é multiplicado por um peso que começa de 11 e que vai sendo diminuido de 1 a cada passo, | |
somando-se as parcelas calculadas: | |
# sm = (5*11)+(4*10)+(6*9)+(4*8)+(7*7)+(1*6)+(4*5)+(2*4)+(9*3)+(4*2) = 299; | |
# Calcula-se o dígito através da seguinte expressão: | |
11 - (sm % 11) = 11 - (299 % 11) = 11 - 2 = 9 | |
-} | |
somatorioDigitoVerificador :: String -> Int -> Int | |
somatorioDigitoVerificador [] n = 0 | |
somatorioDigitoVerificador (x:xs) n = (digitToInt x * n) + somatorioDigitoVerificador xs (n-1) | |
{-- | |
Se o resto da divisão em calculoPrimeiroDigitoVerificador ou calculoSegundoDigitoVerificador calculado | |
for 10 ou 11, o dígito verificador será 0; nos outros casos, o dígito verificador é o próprio resto. | |
--} | |
varificaDigito :: Int -> Int | |
varificaDigito digito | |
| (digito == 10) || (digito == 11) = 0 | |
| otherwise = digito | |
{-- | |
Retorna apenas o digito verificador (primeiro ou segundo digito) do CPF | |
--} | |
digitoVerificador :: Int -> String -> Int | |
digitoVerificador _ [] = 0 | |
digitoVerificador n (x:xs) | |
| n == 1 = digitToInt ( head ( drop 9 (x:xs) ) ) | |
| n == 2 = digitToInt (last (x:xs)) | |
| otherwise = 0 | |
{-- | |
Recebe um cpf FORMATADO e verifica se este eh valido | |
--} | |
validarCpf :: String -> Bool | |
validarCpf [] = False | |
validarCpf "00000000000" = False | |
validarCpf "11111111111" = False | |
validarCpf "22222222222" = False | |
validarCpf "33333333333" = False | |
validarCpf "44444444444" = False | |
validarCpf "55555555555" = False | |
validarCpf "66666666666" = False | |
validarCpf "77777777777" = False | |
validarCpf "88888888888" = False | |
validarCpf "99999999999" = False | |
validarCpf (x:xs) | |
| length (x:xs) < 11 || length (x:xs) > 14 = False -- se cpf for menor que 11 (formado apenas numeros) ou maior que 14 (formato com mascara) eh Falso! | |
| ( calculoPrimeiroDigitoVerificador ( take 9 (x:xs) ) == (digitoVerificador 1 (x:xs)) ) | |
&& ( calculoSegundoDigitoVerificador ( take 10 (x:xs) ) == (digitoVerificador 2 (x:xs)) ) = True | |
| otherwise = False | |
{-- | |
Recebe um cpf NAO FORMATADO e verifica se este eh valido | |
--} | |
isCpf :: String -> Bool | |
isCpf cpf = validarCpf (cpfConverter cpf) | |
{-- | |
Formata o CPF deixando apenas numeros | |
--} | |
cpfConverter :: String -> String | |
cpfConverter s = filter (/='-') ( filter (/='.') s) | |
{-- | |
Faz o processo inverso de cpfConverter convertendo o CPF de apenas numeros | |
para o formato com mascara ex: "###.###.###-##" | |
--} | |
cpfFormat :: String -> String | |
cpfFormat (x:xs) | |
| (length xs) < 3 = [] | |
| otherwise = take 11 ( (take 3 (x:xs)) ++ "." ++ cpfFormat (drop 3 (x:xs)) ) ++ "-" ++ drop 9 (x:xs) |
Parabens amigo, otima iniciativa!
Obrigado!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Parabens amigo, otima iniciativa!