Array
(
    [0] => stdClass Object
        (
            [Votos_Balanceados] => 1
            [id] => 438156
            [titulo] => Validação do número de registro de CNH
            [dataCadastro] => DateTime Object
                (
                    [date] => 2013-03-27 21:27:31
                    [timezone_type] => 3
                    [timezone] => America/Sao_Paulo
                )

            [isFirstPost] => -1
            [idUsuario] => 187402
            [status] => A
            [isExample] => 
            [NomeUsuario] => CLOVIS PERAZZA
            [Apelido] => cps.art
            [Foto] => 
            [Conteudo] => 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; ) )

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

Cps.art
   - 06 mar 2008

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.

Post mais votado

Cps.art
   - 27 mar 2013

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;

Onjahyr
   - 06 mar 2008

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.

Cps.art
   - 06 mar 2008

Obrigado onjahyr.

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

Asales
   - 09 mar 2008

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

Onjahyr
   - 10 mar 2008

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;

Cps.art
   - 10 mar 2008

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.

Asales
   - 11 mar 2008

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

Cps.art
   - 11 mar 2008

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.

Cps.art
   - 03 jul 2009

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.

José Henrique
   - 04 jul 2009

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

Cps.art
   - 04 jul 2009

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.

Emerson
   - 06 jul 2009


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.

Emerson
   - 06 jul 2009

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;


Cps.art
   - 06 jul 2009

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.

Cps.art
   - 07 jul 2009

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.

Emerson
   - 07 jul 2009

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.

Emerson
   - 07 jul 2009

ou talvez para:#Código

    if Digito > 9 then
      Digito := 11 - Digito;

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

Cps.art
   - 07 jul 2009

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

Cps.art
   - 08 jul 2009

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.

Cps.art
   - 08 jul 2009

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.

Provisorio
   - 24 jul 2009

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!