Algoritmos – Validação de CPF

Introdução

Hoje vamos dar uma olhada nos números que compõe um CPF, e ver como é possível calcular os dois últimos dígitos de um CPF — chamados de “verificadores” — a partir dos nove primeiros números.

Validar CPF

A fórmula para validar um número de CPF é conhecida por “módulo 11”, que consiste em gerar um número multiplicando cada dígito por um fator de acordo com a sua posição, depois realizar uma divisão por 11 e gerar o dígito verificador baseado em uma regra usando o resto da divisão. Os dois últimos números do CPF são os dígitos verificadores, cada um deles é calculado usando esta regra, porem com fatores diferentes.

O cálculo do primeiro dígito leva em conta os 9 primeiros números do CPF, o cálculo do segundo leva em conta os 9 primeiros números mais o primeiro dígito verificador. Existe um algoritmo escrito em pseudo-código na Wikipedia — vide links de referências no final do post — que mostra (de forma bem complicada por sinal) como deve ser feito o cálculo.

Fazendo em AdvPL

No último link das referências, encontrei uma explicação um pouco mais simples de como fazer o cálculo. Baseado nesta, montei a função abaixo, que calcula os dois dígitos verificadores de um CPF, partido de uma string contendo os nome primeiros números — sem pontuação ou separadores.

STATIC Function DV_CPF(cCPF)
Local nI , nVL  
Local nM1   := 10 , nM2   := 11
Local nDV1 := 0  , nDV2 := 0
Local nVA := -1  , nEQ := 0 
Local cDV1,cDV2

// Calculo dos valores dos digitos baseado 
// no fator multiplicativo de acordo com a posição 
// de cada dígito 

For nI := 1 to 9
	nVL := val( substr(cCPF,nI,1) )
	nDV1 += (  nVL * nM1 )
	nDV2 += (  nVL * nM2 )
	nM1--
	nM2--
	If nVA >= 0 .AND. nVA == nVL
		nEQ++
	Endif
	nVA := nVL
Next

If nEq == 8
	// Todos os números são iguais - CPF Invalido 
	return ""
Endif

// Determina o primeiro digito verificador 
nDV1 := nDV1 % 11
nDV1 := IIf(nDV1 > 1 , 11 - nDV1 , 0 )
cDv1 := chr(48+nDV1)

// Determina o segundo digito verificador 
nDV2 += (nDV1*nM2)
nDV2 := nDV2 % 11
nDV2 := IIf(nDV2 > 1 , 11 - nDV2 , 0 )
cDv2 := chr(48+nDV2)

// Retorna os dígitos calculados como string
Return cDv1+cDv2

A função recebe uma string contendo os 9 primeiros dígitos do CPF, e retorna os dois últimos dígitos do CPF, ou retorna uma string vazia caso todos os dígitos sejam iguais — o que também caracteriza um número de CPF inválido.

Curiosidades

Com a função acima, realizando 1,2 milhões de cálculos de dígitos de CPF, a média de cálculos por segundo no meu ambiente local variou de 75 a 80 mil cálculos por segundo. Para obter esta métrica, parti de quatro números de CPF em string na memória, para o programa não realizar nenhum I/O. Como esta função usa somente CPU, seu desempenho será proporcional à velocidade do Clock do processador do equipamento utilizado.

E, durante a pesquisa, fiquei sabendo que o último número do CPF — 9o número, antes do primeiro dígito verificador — corresponde a uma região brasileira (agrupando um ou mais estados) onde o CPF foi emitido. Para obter esta informação como String em AdvPL  a partir de um CPF, use o código abaixo:

       
STATIC aCPF_UF := { "Rio Grande do Sul",;
		"Distrito Federal, Goiás, Mato Grosso, Mato Grosso do Sul e Tocantins" ,;
		"Amazonas, Pará, Roraima, Amapá, Acre e Rondônia" ,;
		"Ceará, Maranhão e Piauí" ,;
		"Paraíba, Pernambuco, Alagoas e Rio Grande do Norte",;
		"Bahia e Sergipe" ,;
		"Minas Gerais" ,;
		"Rio de Janeiro e Espírito Santo" ,;
		"São Paulo",;
		"Paraná e Santa Catarina" }

Static Function CPF_UF(cCpf)
Local nVL := val( substr( cCpf ,9,1) ) + 1
Return 	aCPF_UF[nVL]

Por exemplo, todos os CPFs emitidos no estado de São Paulo contém o número “8” antes dos dígitos verificadores.

Conclusão

Por hora, eu acabei de concluir que “Não importa o quanto você saiba sobre um determinado assunto. Uma pesquisa pode mostrar detalhes ou particularidades que você não conhecia e pode ser útil.” — Número do CPF contém um número que identifica uma região onde o documento foi emitido ?! Eu não sabia … 😀

Referências

 

 

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google

Você está comentando utilizando sua conta Google. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s