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

Delphi

06/03/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.


Cps.art

Cps.art

Curtidas 0

Melhor post

Clovis Perazza

Clovis Perazza

27/03/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;
GOSTEI 1

Mais Respostas

Onjahyr

Onjahyr

06/03/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.


GOSTEI 0
Cps.art

Cps.art

06/03/2008

Obrigado onjahyr.

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


GOSTEI 0
Asales

Asales

06/03/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


GOSTEI 0
Onjahyr

Onjahyr

06/03/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;

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

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 – [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]


GOSTEI 0
Cps.art

Cps.art

06/03/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 ([b:25f0df1472]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:25f0df1472]), 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.


GOSTEI 0
Asales

Asales

06/03/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


GOSTEI 0
Cps.art

Cps.art

06/03/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 ´[b:d87629c409]00[/b:d87629c409]´ não validam, assim como alguns terminados em ´[b:d87629c409]01, 02......08, 09[/b:d87629c409]´.

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

Vamos continuar tentando.

Abraços.


GOSTEI 0
Cps.art

Cps.art

06/03/2008

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.


GOSTEI 0
José Henrique

José Henrique

06/03/2008

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


GOSTEI 0
Cps.art

Cps.art

06/03/2008

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:

[b:d9a37c2f07]Conta := (Soma div 11) * 11;
if (Soma - Conta) < 2 then
Dv := 0
else
Dv := 11 - (Soma - Conta);[/b:d9a37c2f07]

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

Vamos continuar tentando.


GOSTEI 0
Emerson Nascimento

Emerson Nascimento

06/03/2008

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.


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

vamos utilzar uma variável para ilustrar melhor:
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.


GOSTEI 0
Emerson Nascimento

Emerson Nascimento

06/03/2008

veja se este código funciona. acabei de montá-lo. testei apenas com dois números de registro de CNH:
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;



GOSTEI 0
Cps.art

Cps.art

06/03/2008

Realmente [b:9122dbfc90]emerson.en[/b:9122dbfc90], 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 [b:9122dbfc90]Digito := StrToInt(CnhN[10]);[/b:9122dbfc90], está errada, deveria ser [b:9122dbfc90]Digito := StrToInt(CnhN[11]);[/b:9122dbfc90], mas mesmo fazenda essa alteração, tambem não funciona.

Tome como exemplo esse número de CNH: [b:9122dbfc90]02650306461[/b:9122dbfc90].
É 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.


GOSTEI 0
Cps.art

Cps.art

06/03/2008

Olá [b:3609038ac3]emercon.en[/b:3609038ac3], 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.


GOSTEI 0
Emerson Nascimento

Emerson Nascimento

06/03/2008

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

para:
    if Digito >= 10 then
      Digito := 1;


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


GOSTEI 0
Emerson Nascimento

Emerson Nascimento

06/03/2008

ou talvez para:
    if Digito > 9 then
      Digito := 11 - Digito;

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


GOSTEI 0
Cps.art

Cps.art

06/03/2008

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.

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


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


Fico no aguardo de novas descobertas.

Abraços


GOSTEI 0
Cps.art

Cps.art

06/03/2008

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 [b:67e98cf075]emerson.en[/b:67e98cf075] 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.


GOSTEI 0
Cps.art

Cps.art

06/03/2008

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

/////////////////////////
[b:04b1d5a323]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;

[color=blue:04b1d5a323]// calcula o digito 1 (10º caractere)[/color:04b1d5a323]
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; // [color=red:04b1d5a323]Aqui está o segredo[/color:04b1d5a323]
Digito1 := 0;
end;

[color=blue:04b1d5a323]// calcula o digito 2 (11º caractere)[/color:04b1d5a323]
Soma := 0;
for j := 9 downto 1 do
Soma := Soma + ( StrToInt(sCNH[j]) * (j)); // [color=red:04b1d5a323]Observem que aqui os multiplicadores estão invertidos[/color:04b1d5a323]
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.[/b:04b1d5a323]
/////////////////////////////////

Testem, depois façam seus comentários.

Abraços.


GOSTEI 0
Provisorio

Provisorio

06/03/2008

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!


GOSTEI 0
Emerson Nascimento

Emerson Nascimento

06/03/2008

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


GOSTEI 0
Provisorio

Provisorio

06/03/2008

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!


GOSTEI 0
Cps.art

Cps.art

06/03/2008

[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.


GOSTEI 0
Cps.art

Cps.art

06/03/2008

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.


[b:b180e1b57e]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;[/b:b180e1b57e]

Teste e depois nos diga se funcionou.

Abraços.


GOSTEI 0
Provisorio

Provisorio

06/03/2008

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!


GOSTEI 0
Provisorio

Provisorio

06/03/2008

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


GOSTEI 0
Cps.art

Cps.art

06/03/2008

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

Logo dou notícias.

Abraços


GOSTEI 0
Cps.art

Cps.art

06/03/2008

Vamos tentar mais uma vez, [b:63f43ee594]Provisorio[/b:63f43ee594].

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.


GOSTEI 0
Cps.art

Cps.art

06/03/2008

Os números de CNHs abaixo, que o [b:6145ec88c1]Provisorio[/b:6145ec88c1] 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


GOSTEI 0
Cps.art

Cps.art

06/03/2008

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


[b:12b1b92828]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;[/b:12b1b92828]


Aguardo retorno de vocês.

Abraços


GOSTEI 0
Provisorio

Provisorio

06/03/2008

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!


GOSTEI 0
Rafael Fig

Rafael Fig

06/03/2008

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!.
GOSTEI 0
Ailtonfinan

Ailtonfinan

06/03/2008

[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.
GOSTEI 0
Ailtonfinan

Ailtonfinan

06/03/2008

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.
GOSTEI 0
Ailtonfinan

Ailtonfinan

06/03/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;

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

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]


GOSTEI 0
Ailtonfinan

Ailtonfinan

06/03/2008

[quote: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:

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.[/quote:f

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

vamos utilzar uma variável para ilustrar melhor:
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.






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.
GOSTEI 0
Ailtonfinan

Ailtonfinan

06/03/2008

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.
GOSTEI 0
Roger Bifarat

Roger Bifarat

06/03/2008

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.
GOSTEI 0
Roger Bifarat

Roger Bifarat

06/03/2008

to em desespero. nao consigo entender! preciso muito dissu
GOSTEI 0
Luciano Chima

Luciano Chima

06/03/2008

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.
GOSTEI 0
Marcelo Freitas

Marcelo Freitas

06/03/2008

Acho que em JavaScript ficaria algo assim (para 11 digitos)

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.
GOSTEI 0
Clovis Perazza

Clovis Perazza

06/03/2008

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;
GOSTEI 0
Jfpimentel

Jfpimentel

06/03/2008

Boa tarde tentei mas nao consegui, será que vc consegui o codigo de segurança da cnh n 02641808140
Obrigado
GOSTEI 0
Clovis Perazza

Clovis Perazza

06/03/2008

Olá Jfpimentel, sobre esse número de registro da CNH 02641808140, o que posso lhe dizer é que é um número válido.
O número é 026418081 e o DV é 40 o que é validado pela função que está neste post.
Essa função valida o número inteiro, ou seja, você fornece o número 02641808140 e a função checa se a CNH 026418081 tem mesmo o DV 40.
Espero ter ajudado.
GOSTEI 0
George Lopes

George Lopes

06/03/2008

Olá, pessoal,

Primeiramente gostaria de agradecer ao Sr. Clovis Perazza, pela contribuição!

Desculpem postar em um tópico antigo... mas acredito que possa ser útil para quem desenvolve em PHP, especialmente no framework Yii.

Usando o mesmo algoritmo de validação para CNH de 11 dígitos, criei um validador para Yii, não fiz muitos testes, mas funcionou com os que já realizei.
O código segue abaixo:

<?php  class cnh extends CValidator {

    /**
     * Validates the attribute of the object.
     * If there is any error, the error message is added to the object.
     * @param CModel the data object being validated
     * @param string the name of the attribute to be validated.
     */
    protected function validateAttribute($object, $attribute) {
        if (!$this->validaCnh($object->$attribute)) {
            $this->addError($object, $attribute, Yii::t('yii', ' não é um número válido.'));
        }
    }

    // Função que valida o número da CNH
    private function validaCnh($pvRegCnh) { // Verifiva se o número digitado contém todos os digitos
        $result = false;

        if (strlen(trim($pvRegCnh)) < 11) { // Caso tenha menos de 11 dígitos
            return false;
        }


        $cnh_forn = substr($pvRegCnh, 0, 9); // Deixa dois dígitos de fora
        $dig_forn = substr($pvRegCnh, 9, 2);
        $incr_dig2 = 0;

        $soma = 0;

        $mult = 9;

        for ($j = 0; $j < 9; $j++) {
            $soma = $soma + (intval(substr($cnh_forn, $j, 1)) * $mult);
            $mult = $mult - 1;
        }

        $digito1 = $soma % 11;

        if ($digito1 == 10) {
            $incr_dig2 = -2;
        }
        if ($digito1 > 9) {
            $digito1 = 0;
        }

        $soma = 0;

        $mult = 1;

        for ($j = 0; $j < 9; $j++) {
            $soma = $soma + (intval(substr($cnh_forn, $j, 1)) * $mult);
            $mult = $mult + 1;
        }

        if ((($soma % 11) * $incr_dig2) < 0) {
            $digito2 = 11 + ($soma % 11) + $incr_dig2;
        }

        if ((($soma % 11) + $incr_dig2) >= 0) {
            $digito2 = ($soma % 11) + $incr_dig2;
        }

        if ($digito2 > 9) {
            $digito2 = 0;
        }

        $dig_enc = strval($digito1) + strval($digito2);

        if ($dig_forn == $dig_enc) {
            return true;
        } else {
            return false;
        }
    }

}
GOSTEI 1
George Lopes

George Lopes

06/03/2008

Caso queiram validar também as CNHs antigas, basta substituir

if (strlen(trim($pvRegCnh)) < 11) { // Caso tenha menos de 11 dígitos
            return false;
}


por

if (strlen(trim($pvRegCnh)) < 11) { // Caso tenha menos de 11 dígitos
            return $this->validaCnhAntiga($pvRegCnh);
}


e acrescentar o método abaixo, dentro da mesma classe:

    private function validaCnhAntiga($pvPguCnh) {

        if (strlen(trim($pvPguCnh)) <> 9) {
            return false;
        }

        $pgu_forn = substr($pvPguCnh, 0, 8);
        $dig_forn = substr($pvPguCnh, 8, 1);

        $soma = 0;
        $mult = 2;
        
        for ($j = 0; $j < 9; $j++) {
            $soma = $soma + (intval(substr($pgu_forn, $j, 1)) * $mult);
        }
        $digito = $soma % 11;

        if ($digito > 9) {
            $digito = 0;
        }
        
        $dig_enc = strval($digito);
        
        if ($dig_forn == $dig_enc) {
            return true;
        } else {
            return false;
        }
        
    }
GOSTEI 0
Clovis Perazza

Clovis Perazza

06/03/2008

Parabéns George pela sua colaboração.
GOSTEI 0
George Lopes

George Lopes

06/03/2008

Na linha 55 coloquei um * onde deveria ser + .

Fiz uns um testes mas infelizmente não funcionou para todas as CNHs de 11 dígitos.
GOSTEI 0
George Lopes

George Lopes

06/03/2008

Deu certo!!!

Gente, na linha 67 da validação de 11 dígitos onde estava:

$dig_enc = strval($digito1) + strval($digito2);


deve ser trocado por

$dig_enc = strval($digito1) . strval($digito2);
GOSTEI 0
Erena

Erena

06/03/2008

Olá,
Desculpe a intromissão porque não sou programadora.
Já pesquisei em todos os lugares possíveis como calcular o DV da minha CNH vencida, sem foto e com 9 dígitos. Não consigo agendar a renovação. E pedi ajuda a universitários (desculpe a piada mas é verdade) com as fórmulas que vocês postaram e eles não conseguiram chegar a nenhum resultado. Eu, sinceramente, não entendo nada.
Se eu colocar meu número aqui será que alguém pode ajudar? Vai ser um favorzão. Se não for possível.....tudo bem, vou cortar os pulsos. Grata
Número: 024847147
Registro: 313609888
RJ
GOSTEI 0
Clovis Perazza

Clovis Perazza

06/03/2008

Erena, sua CNH é do Rio de Janeiro? Qual é o site que você entra pra fazer o agendamento?
Estou perguntando por que aqui no estado de São Paulo eu sei qual é o site e sei como funciona pra fazer o agendamento de renovação.
Tem um lugar no site que pergunta se a CNH é "REGISTRO" ou "PGU".
Esse número (313609888) que você chama de Registro, na verdade é PGU, e o dígito está correto (31360988-8).
Esse outro número (024847147) é o número do Espelho (formulário) e não é solicitado em nenhum caso.
Me passe o link do site onde você tentou fazer o agendamento.
Me retorne depois pra saber se você conseguiu.
Abraços.
GOSTEI 0
Clovis Perazza

Clovis Perazza

06/03/2008

Erena, veja isto.

[img:descricao=Detran RJ - Agendamento Renovação CNH]http://arquivo.devmedia.com.br/forum/imagem/0-20150702-004739.jpg[/img]
GOSTEI 0
Erena

Erena

06/03/2008

Olá,
Valeu pelo retorno tão rápido. O PGU foi aceito e agora diz que o nome de minha mãe está errado. Como tenho que fazer várias modificações, como: nome de casada, endereço/município e o formulário é outro, vou tentar fazer mais tarde, com muita calma. Depois darei o retorno.
O Detran é RJ.
Obrigada, de verdade.
Erena
GOSTEI 0
Willian

Willian

06/03/2008

Desenvolvi a mesma função em PHP, se for útil para alguém; Porém, algumas CNH's não estão sendo validadas com a função, por exemplo, a segunda CNH dessa lista disponibilizada na internet: Lista de CNHs suspensas


    public static function validaCNH($cnh){


        // Subfunção para calcular os dígitos
        function CalculaDigito($identificacao, $digito){

            // Inicializa a variável
            $soma = 0;

            // Atribui o fator de acordo com o dígito a ser calculado
            $digito == 1 ? $fator = 9 : $fator = 1;

            // Percorre os 9 primeiros dígitos da CNH
            for($i = 0; $i < 9; $i++){

                // Multiplica o dígito pelo fator
                $soma += (int)$identificacao[$i] * $fator;

                // Incrementa ou decrementa o fator de acordo com o dígito a ser calculado
                $digito == 1 ? $fator-- : $fator++;
            }

            // Retorna o cálculo do dígito
            return $soma % 11;
        }

        // Verifica se a CNH informada é no modelo novo (11 dígitos)
        if(strlen($cnh) == 11){

            // Recupera os 9 primeiros dígitos da CNH informada
            $identificacao = substr($cnh, 0, 9);

            //Chama a função que faz o cálculo do primeiro dígito
            $digito1 = CalculaDigito($identificacao, 1);

            //Chama a função que faz o cálculo do segundo dígito
            $digito2 = CalculaDigito($identificacao, 2);

            // Se o primeiro dígito é igual a 10, decrementa 2 do segundo
            if($digito1 == 10) $digito2 -= 2;

            // Se for menor que 0, incrementa 11 ao segundo dígito
            if($digito2 < 0) $digito2 += 11;

            // Zera os dígitos caso estes sejam maior que 9
            if($digito1 > 9) $digito1 = 0;
            if($digito2 > 9) $digito2 = 0;

            // Armazena os dígitos do cálculo para efetuar a comparação
            (string)$digitosCalculo = $digito1 . $digito2;

            // Recupera os 2 últimos dígitos verificadores da CNH informada
            $digitos = substr($cnh, 9, 2);

            // Verifica se os dígitos verificadores são iguais ao do cálculo
            if($digitos == $digitosCalculo){

                // Indica que a CNH é válida
                return true;
            }
        }

        // Verifica se a CNH informada é no modelo antigo (9 dígitos)
        if(strlen($cnh) == 9){

            // Recupera os 8 primeiros dígitos da CNH informada
            $identificacao = substr($cnh, 0, 8);

            // Inicializa a variável
            $soma = 0;

            // Inicializa o fator
            $fator = 2;

            // Faz o cálculo do dígito
            for($i = 0; $i < 8; $i++){

                // Multiplica o dígito pelo fator
                $soma += (int)$identificacao[$i] * $fator;

                // Incrementa o fator
                $fator++;
            }

            // Recupera o dígito
            $digitoCalc = $soma % 11;

            // Zera o dígito se for maior que 9
            if($digitoCalc > 9) $digito = 0;

            // Recupera o dígito da CNH informada
            $digitoCnh = substr($cnh, 8, 1);

            // Verifica se o dígito verificador é iguail ao do cálculo
            if($digitoCnh == $digitoCalc){

                // Indica que a CNH é válida
                return true;
            }
        }

        //CNH inválida
        return false;
    }
GOSTEI 0
Clovis Perazza

Clovis Perazza

06/03/2008

William, não entendo nada de PHP, mas quanto ao segundo número da lista não estar validando, provavelmente o Zé Mané que digitou a relação deve ter errado.
Você não imagina o tanto de incompetentes que trabalham nessas repartições.

Um abraço.
GOSTEI 0
Willian

Willian

06/03/2008

Obrigado pela resposta cps.art.

Realmente existe algumas CNH's que não são validadas, mas sempre há a incerteza se o problema está na função ou na CNH, porém, tive em mãos algumas CNHs que foram validadas pelo site do DENATRAN mas não na função.

Já perdi as esperanças de achar um algoritmo que valide 100%, mas caso encontre algo que complemente a função estarei postando aqui.

Abraços.
GOSTEI 0
Clovis Perazza

Clovis Perazza

06/03/2008

Então William, como disse não entendo de PHP, mas verificando seu código achei que devia te dar algumas dicas.
Vamos observar que as CNH NOVAS (Registro) tem 11 dígitos no número e as ANTIGAS (PGU) só 9 dígitos.
Vamos tomar como base a CNH NOVA REGISTRO "00756004182" ( a última da folha 2 da relação de CNHs suspensas do link que você citou).
Ela é NOVA (Registro) pois chequei aqui e validou, porém, se na digitação desse número se suprimir os 2 ZEROS da esquerda, ela passa a ter somente 9 dígitos, o que sugere que ela seja Antiga (PGU) e aí a validação será falsa.
Para que seu código funcione corretamente, é necessário que o USUÁRIO saiba que os zeros devem ser digitados.
O código que postei para validação de CNHs NOVAS (Registro) validam todas elas, e se você conseguir passar para PHP exatamente como o meu, certamente vai validar todas.
Digo isso por que notei que seu código parecer não calcular o SEGUNDO DÍGITO com as particularidades necessárias.
Tente fazer em PHP exatamente como meu código que vai funcionar.
Veja os posts do George Tavares Lopes aqui neste tópico.
Qualquer coisa entre em contato.
Se quiser o meu código completo, me mande seu email que eu te mando.
Abraços a todos.
GOSTEI 0
Rodrigo

Rodrigo

06/03/2008

Amigo consegue ver esse Registro pra mim? 06090265500 ....Valida?
GOSTEI 0
Raimundo Pereira

Raimundo Pereira

06/03/2008

GOSTEI 0
Everson Carvalho

Everson Carvalho

06/03/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 ([b:25f0df1472]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:25f0df1472]), 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.




Me chamou atenção a parte "CPF e RENACH não tem problema". Você teria então a fórmula de cálculo de validação do RENACH?
GOSTEI 0
Rogério Lima

Rogério Lima

06/03/2008

Olá, Pessoal, Boa tarde!
Não sei se este tópico ainda é valido, mas eu fiz uso da ultima versão aqui disponibilizada e em um range de 9mil documentos, alguns deram como invalidos mas teve uma que diz ser invalido, no entanto, ela seria válido. Seria o doc: 22522791500, eu estava utilizando o "Validador Online de CNH" da 4devs.com.br, para certificar que meus registros avaliados estariam corretos ou não e esse doc o site diz que é valido. A checagem do Dv2 retornou 8 que invalidaria a ação em atribuir o "zero" por não ser maior que 9.
Pergunto: alguém saberia dizer que tivemos alguma atualização nesta rotina , quanto aos DV serem iguais a ZEROS...
GOSTEI 0
POSTAR