DevMedia

Validação do número de registro de CNH

0
Olá pessoal.

Já pesquisei em tudo que é forum e não encontrei uma solução definitiva para o cálculo dos Dígitos Verificadores do Registro de CNH.

O número tem 11 dígitos e os 2 últimos são os DV.

Peguei algumas idéias mas não atendem 100¬ dos números, principalmente os que terminam em ´00´.

Se alguem puder dar uma ajuda, ficarei grato.


Publicidade

Respostas (43)

0
Realmente, passei horas no Google procurando e no site do DETRAN e não encontrei nada. Enviei um e-mail ao DETRAN (setor de informática) Se receber alguma informação eu te passo....
Se puder enviar e-mails também poderemos unir as forças (envie para diversos estados, pois se um não souber o outro pode saber)...

Blz.


0
Obrigado onjahyr.

Vou tentar, se conseguir alguma coisa coloco aqui neste tópico.


0
cps.art,
Você já tem a função ou parte da função pronta para testar? Se tiver poste aqui.

Para quem se interessar este é o link para download do documento que regulamenta o documento de cnh:
http://www.denatran.gov.br/download/Resolucoes/resolucao_192_06.doc


0
Mas não informa diretamente como fazer o algorítmo:

18. CÓDIGO NUMÉRICO DE VALIDAÇÃO: com 11 (onze) dígitos gerados a partir de algoritmo específico e de propriedade do DENATRAN, composto pelos dados individuais de cada CNH, permitindo a validação do documento;

=============================================

Art. 2º. O documento de Habilitação terá 2 (dois) números de identificação nacional e 1 (um) número de identificação estadual, que são:

I – o primeiro número de identificação nacional – Registro Nacional, será gerado pelo sistema informatizado da Base Índice Nacional de Condutores – BINCO, composto de 9 (nove) caracteres mais 2 (dois) dígitos verificadores de segurança, sendo único para cada condutor e o acompanhará durante toda a sua existência como condutor, não sendo permitida a sua reutilização para outro condutor.

II – o segundo número de identificação nacional – Número do Espelho da CNH, será formado por 8 (oito) caracteres mais 1 (um) dígito verificador de segurança, autorizado e controlado pelo órgão máximo executivo de trânsito da União, e identificará cada espelho de CNH expedida.

a) O dígito verificador será calculado pela rotina denominada de “módulo 11” e sempre que o resto da divisão for zero (0) ou um (1), o dígito verificador será zero (0);

III – o número de identificação estadual será o número do formulário RENACH, documento de coleta de dados do candidato/condutor gerado a cada serviço, composto, obrigatoriamente, por 11 (onze) caracteres, sendo as duas primeiras posições formadas pela sigla da Unidade de Federação expedidora, facultada a utilização da última posição como dígito verificador de segurança.


0
Olá amigos.

Não montei a função ainda, só estou fazendo testes no Excel para descobrir a forma de calcular esses DVs.

A CNH tem 2 números, 1 em preto, na vertical do lado esquerdo da foto e no verso do lado esquerdo da assinatura do delegado, e é chamdo de ´ESPELHO´, o outro fica abaixo da foto, em vermelho e é chamado de ´REGISTRO´.

O primeiro tem 8 dígitos e um DV, e a informação da letra a) da Res. do Denatran (O dígito verificador será calculado pela rotina denominada de “módulo 11” e sempre que o resto da divisão for zero (0) ou um (1), o dígito verificador será zero (0); ), tambem está furada para o DV do espelho, pois tem espelho com DV 1, o que não poderia acontecer.

Já o segundo número, o REGISTRO, que tem 2 DVs, na maioria dos casos consegui uma forma de validar, porem, para os números que tem DVs ´00´, a mesma regra não se aplica, e para DVs ´01, 02, 03....09´, em alguns casos tambem não.

Trabalho no Detran aqui na minha cidade e cuido do setor de CNH.
Estou tentando montar um sisteminha de protocolo digital para a agencia do Detran aqui da minha cidade, e um para as Auto-Escolas pra agendamento de Provas (Teórica e Prática) para evitar excesso de digitação desnecessária, ou seja, elas me passariam o agendamento em disquetes, e eu compilaria tudo num BD para controle de aprovações e de novos agendamentos, e para isso eu preciso que os números de REGISTRO, assim como CPF e RENACH, fossem validados na digitação para evitar erros.
O CPF e o RENACH não tem problema, mas esse do REGISTRO não há meio de descobrir.

O Denatran não fornece o algorítimo, e não sei porque fazem tanto segredo, se a própria RECEITA FEDERAL forneceu o do DV do CPF e CGC.

Fica então a nosso cargo descobrir isso, mesmo que seja pra auxiliar no próprio serviço do Detran.

Não dá pra entender o que se passa na cabeça desse povo.

Mas vamos tentando que descobriremos.

Abraços.


0
cps.art,

já que vc está utilizando o Excel vc viu este post no link abaixo?
Ele traz duas funções em VBA para validação dos números presentes na CNH.
Se funcionar poste aqui porque fica mais fácil convertê-los para Pascal.

http://forumaccess.com/eve/forums/a/tpc/f/273606921/m/8751053512


0
Olá pessoal.

Já tinha visto esse forum sim.
Já testei o algoritimo que o Mc Feba utiliza e acontece o que eu disse acima, os DVs terminados em ´00´ não validam, assim como alguns terminados em ´01, 02......08, 09´.

Na função dele, quando o Resto = 0 ou Resto = 1, o Resto será 0.
Só isso já invalida o algorítimo, pois tem numeros que tem o último dígito igual a 1.

Vamos continuar tentando.

Abraços.


0
E aí pessoal.

Nada ainda?

Até hoje não consegui nada.
O próprio Detran nem responde meus emails.
Cambada de safados!!!!

Acho que o chefe do Detran do estado de São Paulo não sabe nem o que é CNH.

Se falarem a sigla CNH pra ele, é capaz de pensar que é alguma doença contagiosa, imaginem se ele vai saber o que é ´algoritimo para cálculo de DV de CNH´.

Vai achar que é alguma organização terrorista.

Essas instituições do estado são uma merda mesmo.

Mas vou continuar tentando.

Abraços.


0
Achei esta rotina
http://delphiforall.blogspot.com/2008/09/algortimo-para-validao-de-cnh.html


0
Eu já tinha visto essa rotina José Henrique.

Mas não funciona para todos os números.

Tem número de registro de CNH com dígito 1 (um), então se aplicarmos:

Conta := (Soma div 11) * 11;
if (Soma - Conta) < 2 then
Dv := 0
else
Dv := 11 - (Soma - Conta);


já percebe-se que nunca vai se encontrar o dígito 1.

Vamos continuar tentando.


0

Citação:
Eu já tinha visto essa rotina José Henrique.

Mas não funciona para todos os números.

Tem número de registro de CNH com dígito 1 (um), então se aplicarmos:

#Código
Conta := (Soma div 11) * 11;
if (Soma - Conta) < 2 then
  Dv := 0
else
  Dv := 11 - (Soma - Conta);


já percebe-se que nunca vai se encontrar o dígito 1.

Vamos continuar tentando.


NUNCA VAI ENCONTRAR O DÍGITO 1 ?????
sua afirmação está equivocada.

vamos utilzar uma variável para ilustrar melhor:
#Código
Conta := (Soma div 11) * 11;
DVx := Soma - Conta;
if DVx < 2 then
  Dv := 0
else
  Dv := 11 - DVx;

não há qualquer alteração no código, exceto a atribuição da variável, certo? então...
se DVx resultou em 0 ou 1, Dv será 0.
se DVx resultou em 5, então Dv será 6.
se DVx resultou em 10, qual será o valor de Dv??? tchanammmm.... 1 !!!

de qualquer modo, pulblique alguns números de CNH que você não conseguiu validar com os algoritmos que você encontrou.


0
veja se este código funciona. acabei de montá-lo. testei apenas com dois números de registro de CNH:
#Código
function ValidaCNH(sCNH: string; lExibeMsg: boolean): boolean;
const
  String1 = ´090807060504030201´;
  String2 = ´100908070605040302´;
var
  i,j,Digito: byte;
  Controle, DigitoInformado: string[2];
  StringX: string;
  Soma: smallint;
begin
  sCNH := Copy(´00000000000´+Trim(sCNH),(Length(Trim(sCNH))+11)-10,11 );

  Controle := ´  ´;
  DigitoInformado := Copy( sCNH,10,2 );
  StringX := String1;

  if sCNH <> ´00000000000´ then
  for i := 1 to 2 do
  begin
    Soma := 0;
    if i = 2 then StringX := String2;
    for j := 1 to 9 do
      Soma := Soma + ( StrToInt(sCNH[j]) * StrToIntDef( Copy( StringX,j+(j-1),2 ),0 ) );
    Digito := Soma Mod 11;
    if Digito >= 10 then
      Digito := 0;
    Controle[i] := IntToStr( Digito )[1];
  end;

  Result := Controle = DigitoInformado;

  if not Result and lExibeMsg then
    Application.MessageBox(´Número de CNH inválido!´,´Atenção´,mb_TaskModal + mb_IconWarning);
end;



0
Realmente emerson.en, me enganei qdo disse que não se encontraria dígito 1(um).
Prestando mais atenção no código, percebi meu erro.

Mas a função completa que está no link:
http://delphiforall.blogspot.com/2008/09/algortimo-para-validao-de-cnh.html
não funciona.

Vamos falar da CNH nova, com 11 dígitos no seu número de registro.

Naquela função, a linha que contem Digito := StrToInt(CnhN[10]);, está errada, deveria ser Digito := StrToInt(CnhN[11]);, mas mesmo fazenda essa alteração, tambem não funciona.

Tome como exemplo esse número de CNH: 02650306461.
É o número de minha CNH, válido portanto.

Tente validar esse número com a função do link, alterando a linha que citei acima, depois poste o resultado.

Quanto a essa outra função que você postou, ainda não testei, mas parece ser mais coerente.

Obrigado pela dica, e vão me desculpando por alguma gafe minha, pois sou um iniciante e só pretendo aprender com vocês, e colaborar se me for possível.

Abraços.


0
Olá emercon.en, a função que você postou e que verifica os 2 últimos dígitos da CNH, tambem não funciona.

Teste com o número da CNH que passei no post anterior.

Só valida como verdadeira se alterarmos o último digito (1), por 0(zero).

Vou postar aqui uns 20 números de CNH válidos para testarmos.
Vamos ver se conseguiremos achar esse bendito algoritimo do Detran.

Abraços.


0
ao que parece, basta alterar o trecho:#Código
    if Digito >= 10 then
      Digito := 0;

para:#Código
    if Digito >= 10 then
      Digito := 1;


mas para ter certeza seria necessário mais alguns numeros de CNH.


0
ou talvez para:#Código
    if Digito > 9 then
      Digito := 11 - Digito;

a fórmula correta vai depender dos números a serem calculados.


0
Pelo que andei pesquisando, acho que o número de registro de CNH tem na verdade 2 DV, como o CPF, só que com algoritimo diferente.
Trabalho no Detran aqui na minha cidade exclusivamente com CNH, então, quando da chegada de CNHs novas, 1ª habilitação, e como são feitas em lotes por cada Ciretran, elas vem numa sequência numérica que eu procurei observar, então dá pra perceber que a sequência está nos 9 primeiros dígitos da esquerda para a direita, como é obvio, então os 2 últimos dígitos são os DVs.
Exemplo da sequência que observei:

043973228XY
043973229XY
043973230XY

Tambem ouvi algum cometário que o primeiro dígito, o X da sequência acima, é calculado de forma completamente diferente do Y, algoritimo diferente.

Agora complicou mais ainda.

Pra quem quiser continuar tentando, aí vai uma série de 23 números de CNH para serem testados.

04397322870, 04375701302, 02996843266, 04375700501, 02605113410, 03247061306, 01258750259, 00739751580, 03375637504, 02542551342, 01708111400, 00836510948, 04365445978, 04324384302, 04339482949, 01036520050, 01612581027, 00603454740, 04129251992, 03401740201, 03417248301, 00670431345, 03292694405.


Se encontrarem uma rotina que validem todos eles, certamente essa será a rotina correta.


Fico no aguardo de novas descobertas.

Abraços


0
Viva pessoal, descobri !!!!!!!!!

Testei diversos algoritimos numa planilha excel e acho que descobri o segredo do allgoritimo para o segundo DV.

Para o cálculo do 1º DV, o código do emerson.en tá correto, para o segundo é meio diferente.

Pelo menos os 23 números de CNH que coloquei no post anterior validou 100¬.

Amanhã vou testar mais alguns números para ter certeza, depois vou montar a função e passo pra vocês.

Abraços.


0
Pois bem pessoal, como prometi ai vai a função.

/////////////////////////
function VRegCNH(nCNH: string): boolean;

var
j, Soma, Digito1, Digito2, Incr_dig2: integer;
sCNH, Dig_Forn, Dig_Enc : string;
begin
Result := False;

if length(Trim(nCNH)) < 11 then
Exit;

sCNH := Copy(nCNH,1,9);

Dig_Forn := Copy(nCNH,10,2);

Incr_Dig2 := 0;

// calcula o digito 1 (10º caractere)
Soma := 0;
for j := 9 downto 1 do
Soma := Soma + ( StrToInt(sCNH[j]) * (10-j));
Digito1 := Soma Mod 11;
if Digito1 >= 10 then
begin
Incr_Dig2 := -2; // Aqui está o segredo
Digito1 := 0;
end;

// calcula o digito 2 (11º caractere)
Soma := 0;
for j := 9 downto 1 do
Soma := Soma + ( StrToInt(sCNH[j]) * (j)); // Observem que aqui os multiplicadores estão invertidos
Digito2 := Soma Mod 11;
if Digito2 >= 10 then
begin
Digito2 := 0;
end;

Digito2 := Digito2 + Incr_Dig2;

Dig_Enc := IntToStr(Digito1)+IntToStr(Digito2);

Result := Dig_Forn = Dig_enc;

end;
end.

/////////////////////////////////

Testem, depois façam seus comentários.

Abraços.


0
A função apresentada está quase correta!

Digo ´quase´, pois num laço de repetição que testei uma massa de 3123 números de CNH, apenas 90 não validaram por esta função. Porém estas 90 são CNHs válidas, como pode ser verificado em sites do DETRAN.

Exemplos de CNHs válidas (que não validaram com essa função) são:
112274500 - 113473508 - 115478700 - 134934008 - 138273900 - 138876109 - 186499700 - 218659309 - 219077908 - 241595908 - 293766109 - 293821800 - 301823609 - 307412830 - 308041097 - 308510968 - 308601149 - 308656679 - 309493455 - 309508711 - 309626331 - 310376408 - 313736375 - 314019286 - 314035249 - 315040424 - 315097256 - 315259515 - 315323140 - 315558600 - 316629073 - 317775758 - 318109778 - 318490102 - 318494361 - 327244208 - 330157409 - 374723809 - 413981908 - 416345009 - 530678608 - 679221808 - 697159700 - 709245709 - 715334009 - 804310709 - 869586408 - 894476709

Para conseguir a lista com as 3123 CNHs, basta acessar
http://www.detran.rj.gov.br/_monta_aplicacoes.asp?doc=5646&cod=14&tipo=exibe_noticias&pag_noticias=true

E para testar o dígito verificador oficialmente pelo Detran, podemos usar o link https://wwws.detrannet.mg.gov.br/detran/pontuacond.asp?IdServico=36

Verifiquem. Estou tentando achar qual é o erro. De qualquer maneira, o algoritmo é muito bom, e valida na grande maioria dos casos (apenas 3¬ de erro), porém meio erro ainda é um erro.

Vamos tentar achar um algoritmo que valide 100¬ dos números que passei?

Abraços a todos!


0
essa rotina foi desenvolvida para validar as CNHs novas, de 11 dígitos.


0
Não, na verdade esta rotina validou todas as que tinham 7 e 8 dígitos! E não foram poucas! O esquema que deve ser feito é antes de começar os cálculos, acrescentar com zeros à esquerda até completar os 11 algarismos.

A maioria que não validou teve 9 dígitos.

Faça o teste...

Abraços!


0
Provisório, o que o emerson.en disse está correto.
Essa função que postei aqui é para validar CNHs novas, de 11 dígitos, ou seja, 9 dígitos + 2 verificadores. Ex: 123.456.789-01.

Para validar as CNHs antigas, as chamadas PGU, de 8 dígitos mais 1 DV, o algoritimo é diferente.

Fiz uma correção na função que postei anteriormente, então fica assim:


FUNCTION VRegCnh(PVRegCnh : string) : string; stdcall;

var
j, Soma, Digito1, Digito2, Incr_dig2: integer;
CNH_Forn, Dig_Forn, Dig_Enc : string;

begin
Result := ´F´;

if length(Trim(PVRegCnh)) < 11 then
Exit;

CNH_Forn := Copy(PVRegCnh,1,9);

Dig_Forn := Copy(PVRegCnh,10,2);

Incr_Dig2 := 0;

// calcula o digito 1 (10º caractere)
Soma := 0;
for j := 9 downto 1 do
Soma := Soma + ( StrToInt(CNH_Forn[j]) * (10-j));
Digito1 := Soma Mod 11;
if Digito1 >= 10 then
begin
Incr_Dig2 := -2; // Aqui está o segredo
Digito1 := 0;
end;

// calcula o digito 2 (11º caractere)
Soma := 0;
for j := 9 downto 1 do
Soma := Soma + ( StrToInt(CNH_Forn[j]) * (j));
Digito2 := (Soma Mod 11) + Incr_Dig2; // soma o incremento aqui
if Digito2 >= 10 then
begin
Digito2 := 0;
end;

// Digito2 := Digito2 + Incr_Dig2; // tira esta linha

Dig_Enc := IntToStr(Digito1)+IntToStr(Digito2);

if Dig_Forn = Dig_enc then
begin
Result := ´V´;
end;

if Dig_Forn <> Dig_enc then
begin
Result := ´F´;
end;

end;


Essa alteração é por que o segundo dígito poderia ser tambem maior que 9, o que faria ele ser ´0´ (zero), e se o primeiro tambem tivesse sido maior que 9, o incremento seria -2, então o segundo seria ´0-2=-2´ o que seria incorreto.


Vou passar a função para validar CNHs antigas, na próxima mensagem.


0
Esta função valida as CNHs antigas.

É um algoritimo comum, igual ao que valida conta de banco e a maioria dos numeros com DV.
Existem 2 maneiras de se tratar o dígito verificador neste módulo.

1º) Algumas empresas não utiliza ´X´ como dígito, então se o resultado da operação for igual a ´10´, o dígito será ´0´. É o caso das CNHs antigas.

2º) Outras empresas, bancos principalmente, utiliza o ´X´ como dígito, então se o resultado da operação for ´10´ o dígito será ´X´.

Eu não utilizo esta função de validar CNHs antigas por que no meu trabalho não tenho essa necessidade, só utilizo validação de CNHs novas.
Se você tiver a necessidade de utilizar as 2 funções, pode juntar as 2 numa só, definindo no início da função se é CNH nova ou se é CNH antiga pela quantidade de caracteres, ai direciona para o cálculo pretendido.

No meu modo de entender, todos os caracteres do numero devem ser digitados, ou seja os zeros no início, para que a função possa distinguir cada tipo de CNH.
Se existirem 11 caracteres é CNH nova, se existirem 9 caracteres é CNH antiga.

Ai abaixo vai a função para as CNHs antigas.


FUNCTION VMod110(PVMod110 : string) : string; stdcall;
var

LenPVMod110 : integer;
MultVMod110 : integer;
SomaVMod110 : integer;
PVMod110New : string;
PVMod110Dig : string;
kvm : integer;
DigMod110 : string;

begin

MultVMod110 := 9;
SomaVMod110 := 0;
PVMod110 := trim(PVMod110);
LenPVMod110 := length(PVMod110);
PVMod110New := Copy(PVMod110,1,LenPVMod110 - 1);
PVMod110Dig := Copy(PVMod110,LenPVMod110,1);

if LenPVMod110 < 2 then
begin
Result := ´F´;
Exit;
end;

if StrToInt(PVMod110New) < 1 then
begin
Result := ´F´;
Exit;
end;

for kvm := LenPVMod110 - 1 downto 1 do
begin
SomaVMod110 := SomaVMod110 + (MultVMod110 * StrToInt(Copy(PVMod110New,kvm,1)));
MultVMod110 := MultVMod110 - 1;
if MultVMod110 = 1 then
begin
MultVMod110 := 9
end;
end;

DigMod110 := IntToStr(SomaVMod110 mod 11);

if DigMod110 = ´10´ then
begin
DigMod110 := ´0´
end;

PVMod110New := PVMod110New + DigMod110;

if PVMod110 = PVMod110New then
Result := ´V´
else begin
Result := ´F´
end;

end;


Teste e depois nos diga se funcionou.

Abraços.


0
Obrigado pela atenção e interesse!

Testei as novas funções com os 3123 números. Testei a que valida as novas e as antigas, porém algumas (71 cnhs) que validam pelo site do Detran ainda não validam com estas funções.

Alguns exemplos são:

112274500
115478700
138273900
138876109
186499700
218659309
293766109
293821800
301823609
315558600
330157409
374723809
416345009
697159700
709245709
715334009
804310709
894476709

e

01137369409
01217567509
01417566409
01422691909

Estamos quase conseguindo, pois 71 em um universo de 3123 é um número bastante pequeno, porém...

De qualquer forma, agradeço imensamente pelas funções e explicação adicional!

Um abração!


0
E então, conseguiu mais alguma maneira?
Eu não consegui passar deste percentual ainda...


0
Olá pssoal.
Fiqui uns dias sem micro, meu monitor pifou, estou usando um emprestado até chegar um novo.

Logo dou notícias.

Abraços


0
Vamos tentar mais uma vez, Provisorio.

Mudei algumas coisas na função, veja aí se valida todas agora.

Só as CNHs novas, com número de registro de 11 dígitos.


FUNCTION VRegCnh(PVRegCnh : string) : string; stdcall;

var
j, Mult, Soma, Digito1, Digito2, Incr_dig2: integer;
CNH_Forn, Dig_Forn, Dig_Enc : string;

begin
Result := ´F´;

if length(Trim(PVRegCnh)) < 11 then
Exit;

CNH_Forn := Copy(PVRegCnh,1,9);

Dig_Forn := Copy(PVRegCnh,10,2);

Incr_Dig2 := 0;


Soma := 0;
Mult := 9;
for j := 1 to 9 do
begin
Soma := Soma + (StrToInt(CNH_Forn[j]) * Mult);
Mult := Mult - 1;
end;
Digito1 := Soma Mod 11;
if Digito1 = 10 then
begin
Incr_Dig2 := -2;
end;
if Digito1 > 9 then
begin
Digito1 := 0;
end;


Soma := 0;
Mult := 1;
for j := 1 to 9 do
begin
Soma := Soma + (StrToInt(CNH_Forn[j]) * Mult);
Mult := Mult + 1;
end;

if (Soma Mod 11) + Incr_Dig2 < 0 then
begin
Digito2 := 11 + (Soma Mod 11) + Incr_Dig2;
end;

if (Soma Mod 11) + Incr_Dig2 >= 0 then
begin
Digito2 := (Soma Mod 11) + Incr_Dig2;
end;


if Digito2 > 9 then
begin
Digito2 := 0;
end;

Dig_Enc := IntToStr(Digito1)+IntToStr(Digito2);

if Dig_Forn = Dig_enc then
begin
Result := ´V´;
end;

if Dig_Forn <> Dig_enc then
begin
Result := ´F´;
end;

end;

Abraços a todos.


0
Os números de CNHs abaixo, que o Provisorio colocou na mensagem, e que não valida o DV, apesar de conterem somente 9 dígitos, não são números de CNHs antigas, o tal de PGU, basta acrescentar dois zeros a esquerda e checa-las como CNH nova, nessa função que postei acima, que os DV validam.
É que os números foram tomados como ´inteiros´ e os zeros foram suprimidos, por isso a importancia de se tratar os números de CNH considerando os zeros.

Essas abaixo são números de CNHs novas, basta acrescentar os 2 zeros a esquerda:

112274500
115478700
138273900
138876109
186499700
218659309
293766109
293821800
301823609
315558600
330157409
374723809
416345009
697159700
709245709
715334009
804310709
894476709

Para validar os números de CNHs antigas, os PGUs, que são 9 dígitos, sendo os 8 primeiros a numeração sequencial e o último a direita (nono), o DV, vou postar logo abaixo a função.

Abraços


0
Ai vai a função para checar números de CNHs antigas, os PGUs.


FUNCTION VPguCnh(PVPguCnh : string) : string; stdcall;

var
j, Mult, Soma, Digito : integer;
PGU_Forn, Dig_Forn, Dig_Enc : string;

begin

Result := ´F´;

if length(Trim(PVPguCnh)) <> 9 then
Exit;

PGU_Forn := Copy(PVPguCnh,1,8);

Dig_Forn := Copy(PVPguCnh,9,1);


Soma := 0;
Mult := 2;
for j := 1 to 8 do
begin
Soma := Soma + (StrToInt(PGU_Forn[j]) * Mult);
Mult := Mult + 1;
end;
Digito := Soma Mod 11;

if Digito > 9 then
begin
Digito := 0;
end;


Dig_Enc := IntToStr(Digito);


if Dig_Forn = Dig_enc then
begin
Result := ´V´;
end;

if Dig_Forn <> Dig_enc then
begin
Result := ´F´;
end;

end;



Aguardo retorno de vocês.

Abraços


0
Meu amigo cps.art, desculpa a demora ao responder... mas é que depois de diariamente verificar que não tinha resposta, então abandonei o forum por uns tempos!

Quero agradecer por postar a única solução que realmente funciona para todos os CNHs!

PARABÉNS por desenvolver o único algoritmo que desvendou o cálculo do DV da CNH! Esse algoritmo não foi divulgado e você foi o único que realmente o desvendou!

Valeu pela força! Agora, os milhares de CNHs estão validando 100¬!
Obrigado!
Abraços e sucesso!


0
Pessoal,

Estava a procura de como validar a CNH, encontrei esse tópico que parece ter achado uma solução funcional.

cps.art, poderia publicar a explicação da solução? Como um algoritmo ou solução descritiva para que seja possível qualquer pessoa implementar em outras linguagens.

É validação Módulo 11 com alguma característica particular?

Grato!.
0

Citação:
[b:8147beb8c0]Provisório[/b:8147beb8c0], o que o [b:8147beb8c0]emerson.en[/b:8147beb8c0] disse está correto.
Essa função que postei aqui é para validar CNHs novas, de 11 dígitos, ou seja, 9 dígitos + 2 verificadores. Ex: 123.456.789-01.

Para validar as CNHs antigas, as chamadas PGU, de 8 dígitos mais 1 DV, o algoritimo é diferente.

Fiz uma correção na função que postei anteriormente, então fica assim:


[b:8147beb8c0]FUNCTION VRegCnh(PVRegCnh : string) : string; stdcall;

var
j, Soma, Digito1, Digito2, Incr_dig2: integer;
CNH_Forn, Dig_Forn, Dig_Enc : string;

begin
Result := ´F´;

if length(Trim(PVRegCnh)) < 11 then
Exit;

CNH_Forn := Copy(PVRegCnh,1,9);

Dig_Forn := Copy(PVRegCnh,10,2);

Incr_Dig2 := 0;

// calcula o digito 1 (10º caractere)
Soma := 0;
for j := 9 downto 1 do
Soma := Soma + ( StrToInt(CNH_Forn[j]) * (10-j));
Digito1 := Soma Mod 11;
if Digito1 >= 10 then
begin
Incr_Dig2 := -2; // Aqui está o segredo
Digito1 := 0;
end;

// calcula o digito 2 (11º caractere)
Soma := 0;
for j := 9 downto 1 do
Soma := Soma + ( StrToInt(CNH_Forn[j]) * (j));
Digito2 := (Soma Mod 11) + Incr_Dig2; // [color=red:8147beb8c0]soma o incremento aqui[/color:8147beb8c0]
if Digito2 >= 10 then
begin
Digito2 := 0;
end;

// Digito2 := Digito2 + Incr_Dig2; // [color=red:8147beb8c0]tira esta linha[/color:8147beb8c0]

Dig_Enc := IntToStr(Digito1)+IntToStr(Digito2);

if Dig_Forn = Dig_enc then
begin
Result := ´V´;
end;

if Dig_Forn Dig_enc then
begin
Result := ´F´;
end;

end;[/b:8147beb8c0]

Essa alteração é por que o segundo dígito poderia ser tambem maior que 9, o que faria ele ser ´0´ (zero), e se o primeiro tambem tivesse sido maior que 9, o incremento seria -2, então o segundo seria ´0-2=-2´ o que seria incorreto.


Vou passar a função para validar CNHs antigas, na próxima mensagem.




fale amigo blz me chamo ailton
saber nao sou progamador igual há vcs minha funçao e outra mas interecei na area que vcs exercem estou aki nao pra da opiniao mas sim pra gente ganha dinheiro se intereca a vc entre em contato nesse mesmo endereço pop.ailton@hotmail.com
esse tambem e meu msn blz aguardo resposta de vc abraço. e muito simples e facio. geralmente ou quase o dia todo on line pelo msn ok.
0

Citação:
Achei esta rotina
http://delphiforall.blogspot.com/2008/09/algortimo-para-validao-de-cnh.html




fale amigo blz me chamo ailton
saber nao sou progamador igual há vcs minha funçao e outra mas interecei na area que vcs exercem estou aki nao pra da opiniao mas sim pra gente ganha dinheiro se intereca a vc entre em contato nesse mesmo endereço pop.ailton@hotmail.com
esse tambem e meu msn blz aguardo resposta de vc abraço. e muito simples e facio. geralmente ou quase o dia todo on line pelo msn ok.
0

Citação:
Mas não informa diretamente como fazer o algorítmo:

18. CÓDIGO NUMÉRICO DE VALIDAÇÃO: com 11 (onze) dígitos gerados a partir de algoritmo específico e de propriedade do DENATRAN, composto pelos dados individuais de cada CNH, permitindo a validação do documento;

=============================================

Art. 2º. O documento de Habilitação terá 2 (dois) números de identificação nacional e 1 (um) número de identificação estadual, que são:

I – o primeiro número de identificação nacional – Registro Nacional, será gerado pelo sistema informatizado da Base Índice Nacional de Condutores – BINCO, composto de 9 (nove) caracteres mais 2 (dois) dígitos verificadores de segurança, sendo único para cada condutor e o acompanhará durante toda a sua existência como condutor, não sendo permitida a sua reutilização para outro condutor.


fale amigo blz me chamo ailton
saber nao sou progamador igual há vcs minha funçao e outra mas interecei na area que vcs exercem estou aki nao pra da opiniao mas sim pra gente ganha dinheiro se intereca a vc entre em contato nesse mesmo endereço pop.ailton@hotmail.com
esse tambem e meu msn blz aguardo resposta de vc abraço. e muito simples e facio. geralmente ou quase o dia todo on line pelo msn ok.
II – [b:222657da1c]o segundo número de identificação nacional – Número do Espelho da CNH, será formado por 8 (oito) caracteres mais 1 (um) dígito verificador de segurança, autorizado e controlado pelo órgão máximo executivo de trânsito da União, e identificará cada espelho de CNH expedida.[/b:222657da1c]

a) [b:222657da1c]O dígito verificador será calculado pela rotina denominada de “módulo 11” e sempre que o resto da divisão for zero (0) ou um (1), o dígito verificador será zero (0); [/b:222657da1c]

III – o número de identificação estadual será o número do formulário RENACH, documento de coleta de dados do candidato/condutor gerado a cada serviço, composto, [b:222657da1c]obrigatoriamente, por 11 (onze) caracteres, sendo as duas primeiras posições formadas pela sigla da Unidade de Federação expedidora, facultada a utilização da última posição como dígito verificador de segurança.[/b:222657da1c]


0

Citação:

Citação:
:f3064a86dd=´cps.art´]Eu já tinha visto essa rotina José Henrique.

Mas não funciona para todos os números.

Tem número de registro de CNH com dígito 1 (um), então se aplicarmos:

#Código
:1:f3064a86dd]Conta := (Soma div 11) * 11;
if (Soma - Conta) < 2 then
  Dv := 0
else
  Dv := 11 - (Soma - Conta);
:1:f3064a86dd]

já percebe-se que nunca vai se encontrar o dígito 1.

Vamos continuar tentando.
:f

NUNCA VAI ENCONTRAR O DÍGITO 1 ?????
sua afirmação está equivocada.

vamos utilzar uma variável para ilustrar melhor:
#Código
:1:f3064a86dd]Conta := (Soma div 11) * 11;
DVx := Soma - Conta;
if DVx < 2 then
  Dv := 0
else
  Dv := 11 - DVx;
:1:f3064a86dd]
não há qualquer alteração no código, exceto a atribuição da variável, certo? então...
se DVx resultou em 0 ou 1, Dv será 0.
se DVx resultou em 5, então Dv será 6.
se DVx resultou em 10, qual será o valor de Dv??? tchanammmm.... 1 !!!

de qualquer modo, pulblique alguns números de CNH que você não conseguiu validar com os algoritmos que você encontrou.






fale amigo blz me chamo ailton
saber nao sou progamador igual há vcs minha funçao e outra mas interecei na area que vcs exercem estou aki nao pra da opiniao mas sim pra gente ganha dinheiro se intereca a vc entre em contato nesse mesmo endereço pop.ailton@hotmail.com
esse tambem e meu msn blz aguardo resposta de vc abraço. e muito simples e facio. geralmente ou quase o dia todo on line pelo msn ok.
0

Citação:
A função apresentada está quase correta!

Digo ´quase´, pois num laço de repetição que testei uma massa de 3123 números de CNH, apenas 90 não validaram por esta função. Porém estas 90 são CNHs válidas, como pode ser verificado em sites do DETRAN.

Exemplos de CNHs válidas (que não validaram com essa função) são:
112274500 - 113473508 - 115478700 - 134934008 - 138273900 - 138876109 - 186499700 - 218659309 - 219077908 - 241595908 - 293766109 - 293821800 - 301823609 - 307412830 - 308041097 - 308510968 - 308601149 - 308656679 - 309493455 - 309508711 - 309626331 - 310376408 - 313736375 - 314019286 - 314035249 - 315040424 - 315097256 - 315259515 - 315323140 - 315558600 - 316629073 - 317775758 - 318109778 - 318490102 - 318494361 - 327244208 - 330157409 - 374723809 - 413981908 - 416345009 - 530678608 - 679221808 - 697159700 - 709245709 - 715334009 - 804310709 - 869586408 - 894476709

Para conseguir a lista com as 3123 CNHs, basta acessar
http://www.detran.rj.gov.br/_monta_aplicacoes.asp?doc=5646&cod=14&tipo=exibe_noticias&pag_noticias=true

E para testar o dígito verificador oficialmente pelo Detran, podemos usar o link https://wwws.detrannet.mg.gov.br/detran/pontuacond.asp?IdServico=36

Verifiquem. Estou tentando achar qual é o erro. De qualquer maneira, o algoritmo é muito bom, e valida na grande maioria dos casos (apenas 3¬ de erro), porém meio erro ainda é um erro.

Vamos tentar achar um algoritmo que valide 100¬ dos números que passei?

Abraços a todos!






fale amigo blz me chamo ailton
saber nao sou progamador igual há vcs minha funçao e outra mas interecei na area que vcs exercem estou aki nao pra da opiniao mas sim pra gente ganha dinheiro se intereca a vc entre em contato nesse mesmo endereço pop.ailton@hotmail.com
esse tambem e meu msn blz aguardo resposta de vc abraço. e muito simples e facio. geralmente ou quase o dia todo on line pelo msn ok.
0
Boa tarde pessoal. preciso de ajuda. se possivel, nao entendo nada de dephi, porem necessito desvendar as dvs das cnhs nao preciso nem validar 100% alguem por favor me ajuda. podemos trocar favores.
0
to em desespero. nao consigo entender! preciso muito dissu
0
Alguém sabe a formula matemática para calcular o digito verificador do número de identificação nacional – Número do Espelho da CNH, será formado por 8 (oito) caracteres mais 1 (um) dígito verificador de segurança, autorizado e controlado pelo órgão máximo executivo de trânsito da União, e identificará cada espelho de CNH expedida.
0
Acho que em JavaScript ficaria algo assim (para 11 digitos)

#Código
function VRegCnh(PVRegCnh)
{
var Soma, Digito1, Digito2, Incr_dig2; //: integer;
var CNH_Forn, Dig_Forn, Dig_Enc;// : string;

if (PVRegCnh.length != 11)
	return
	
CNH_Forn = PVRegCnh.slice(0,9);
Dig_Forn = PVRegCnh.slice(9);

Incr_Dig2 = 0;

// calcula o digito 1 (10º caractere)
Soma = 0;
Mult = 9;

for(j=1;j 9)
		{
		Digito1 = 0;
		}
	
// calcula o digito 2 (11º caractere)
Soma = 0;
Mult = 1;
for (j=1; j= 10)
			{
			Digito2 = 0;
			}	
		
//alert("PVRegCnh:"+PVRegCnh+" | CNH_Forn:"+CNH_Forn+" | Dig_Forn:"+Dig_Forn+" | Digito1:"+Digito1+" | Digito2:"+Digito2);

if (Digito1 != PVRegCnh[9] || Digito2 != PVRegCnh[10])
	{return "V";}//alert("A CNH está incorreta!\n\nOs dígitos verificadores são inválidos!");}
else
    return "F";
}


Desculpa por responder isso na sala de Delphi, mas acho que o tópico tem mais a ver com a validação que com a linguagem.
0
A função de validação de números de registro de CNHs novas (com foto) vai abaixo:



FUNCTION VRegCnh(PVRegCnh : string) : string; stdcall;

var
j, Mult, Soma, Digito1, Digito2, Incr_dig2: integer;
CNH_Forn, Dig_Forn, Dig_Enc : string;

begin
Result := F;

if length(Trim(PVRegCnh)) < 11 then
Exit;

CNH_Forn := Copy(PVRegCnh,1,9);

Dig_Forn := Copy(PVRegCnh,10,2);

Incr_Dig2 := 0;

Soma := 0;
Mult := 9;
for j := 1 to 9 do
begin
Soma := Soma + (StrToInt(CNH_Forn[j]) * Mult);
Mult := Mult - 1;
end;
Digito1 := Soma Mod 11;
if Digito1 = 10 then
begin
Incr_Dig2 := - 2;
end;
if Digito1 > 9 then
begin
Digito1 := 0;
end;

Soma := 0;
Mult := 1;
for j := 1 to 9 do
begin
Soma := Soma + (StrToInt(CNH_Forn[j]) * Mult);
Mult := Mult + 1;
end;

if (Soma Mod 11) + Incr_Dig2 < 0 then
begin
Digito2 := 11 + (Soma Mod 11) + Incr_Dig2;
end;

if (Soma Mod 11) + Incr_Dig2 >= 0 then
begin
Digito2 := (Soma Mod 11) + Incr_Dig2;
end;

if Digito2 > 9 then
begin
Digito2 := 0;
end;

Dig_Enc := IntToStr(Digito1)+IntToStr(Digito2);

if Dig_Forn = Dig_enc then
begin
Result := V;
end;

if Dig_Forn Dig_enc then
begin
Result := F;
end;

end;
0
LUCIANO F CHIMA, tente utilizar o algoritimo MODULO 11, usado para calcular dígito de contas de bancos, com a diferença que no número identificador da CNH não tem dígito "X".
Veja abaixo se essa função te ajuda.




FUNCTION VMod110(PVMod110 : string) : string;
var
LenPVMod110 : integer;
MultVMod110 : integer;
SomaVMod110 : integer;
PVMod110New : string;
PVMod110Dig : string;
kvm : integer;
DigMod110 : string;

begin

MultVMod110 := 9;
SomaVMod110 := 0;
PVMod110 := trim(PVMod110);
LenPVMod110 := length(PVMod110);
PVMod110New := Copy(PVMod110,1,LenPVMod110 - 1);
PVMod110Dig := Copy(PVMod110,LenPVMod110,1);

if LenPVMod110 < 2 then
begin
Result := F;
Exit;
end;

if StrToInt(PVMod110New) < 1 then
begin
Result := F;
Exit;
end;

for kvm := LenPVMod110 - 1 downto 1 do
begin
SomaVMod110 := SomaVMod110 + (MultVMod110 * StrToInt(Copy(PVMod110New,kvm,1)));
MultVMod110 := MultVMod110 - 1;
if MultVMod110 = 1 then
begin
MultVMod110 := 9
end;
end;

DigMod110 := IntToStr(SomaVMod110 mod 11);

if DigMod110 = 10 then
begin
DigMod110 := 0
end;

PVMod110New := PVMod110New + DigMod110;

if PVMod110 = PVMod110New then
Result := V
else begin
Result := F
end;

end;