[Rio-pm] Verificador CPF/CGC/CNPJ

Adriano Ferreira a.r.ferreira em gmail.com
Quarta Maio 2 17:42:47 PDT 2007


On 5/2/07, breno <breno at rio.pm.org> wrote:
> Excelente, Adriano!
>
> E vc já comparou o algoritmo do CheckDigits com o seu?

A maioria destas implementações não traz muita novidade. É basicamente
o algoritmo do código Java mostrado. Quanto à questão de eficiência,
isto vai depender bastante de benchmarks para identificar as
construções mais rápidas. Eu não fiz este tipo de trabalho.

Uma pequena modificação que usei foi ao invés de calcular os dígitos
de verificação e compará-los para a validação, foram desenvolvidas
equações de verificação do tipo

     f( c1, ..., cn ) = x1
ou
     f( c1, ..., cn ) = x2

onde c1 até cn envolvem todos os dígitos (inclusive os de verificação).

Ah, é fácil de se enganar destas equações e implementar errado o
algoritmo. Uma busca na Internet mostra alguns algoritmos errados e
algumas variantes. Estas variantes acho que podem ser provadas
equivalentes matematicamente.

> Aliás, pode dar uma explanada geral sobre onde as fórmulas foram
> encontradas? Isto é, quais seriam os testes típicos para essa entrada?

Procurei fontes oficiais, mas como eles não se preocupam muito com
isso, acabei encontrando pela Internet fontes (aparentemente)
confiáveis. Alguns testes com CPFs, CNPJs, etc. válidos me deram mais
confiança nestas fórmulas. Agora os IEs estão documentados no
Sintegra, cada um de uma forma mas pelo menos tem uma documentação
oficial.

Digo
> isso pois alguns verificadores ignoram as entradas "canônicas" como "
> 111.111.111-11", por exemplo. Existem outras desse tipo? Nos seus arquivos
> de testes do BR::Ids tem comparações de 10 CPFs válidos, mas a verificação
> aleatória testa muito mais se não me engano (por isso perguntei).

A verificação aleatória é um teste de quem nasceu primeiro, o ovo ou a
galinha. Se algum teste encontrar um problema, as equações tem de ser
revisadas.

> Puxa, será que o Paul e o Mathias estão na Rio-PM tb? Ia ser uma discussão
> interessante ;-)

Quanto aos dígitos viciados, hoje eu não os trato. Assim
000.000.000-00 é um CPF válido atualmente.

> []s
>
> -b
>
>
> On 5/2/07, Adriano Ferreira < a.r.ferreira at gmail.com> wrote:
> > Além dos módulos que você encontrou tem também
> >
> >
> http://search.cpan.org/~mamawe/Algorithm-CheckDigits-0.44/CheckDigits/M11_004.pm
> >
> > que consegue tratar CPFs e título eleitoral.
> >
> > On 5/2/07, Adriano Ferreira <a.r.ferreira at gmail.com> wrote:
> > > On 5/1/07, breno <breno at rio.pm.org> wrote:
> > > > Pessoal, olha a vergonha!!!
> > > >
> > > > Achei na Internet um verificador em Java de CPF ***E*** CGC/CNPJ com
> apenas
> > > > 35 linhas, incluindo espaços e "fecha-chaves". Procurando no CPAN,
> encontrei
> > > > um módulo de verificação de CPF com 29 linhas (sem contar os espaços!)
> e um
> > > > de CGC/CNPJ com 76 (!!!!) linhas, também sem contar os espaços...
> > > >
> > > > O que acham de fazermos uma versão mais eficiente (e de preferencia
> mais
> > > > enxuta) desses verificadores em Perl, hein?!
> > > >
> > > > Tá lançado o desafio (e possível golfe em paralelo) para a
> comunidade!!! O
> > > > melhor código vai pro novo site, e de repente até pro CPAN!!!
> > > >
> > > > []s
> > > >
> > > > -b
> > > >
> > > > Para os que ficaram interessados, os links para os módulos do CPAN (do
> Paul
> > > > Hodel) estão em:
> > > >
> http://search.cpan.org/~hodel/Brasil-Checar-CPF-1.01a/Checar/CPF/CPF.pm
> > > >
> http://search.cpan.org/~hodel/Brasil-Checar-CGC-1.01a/Checar/CGC/CGC.pm
> > > >
> > > > Antes de enviar esse email procurei um pouco mais pelo CPAN e
> encontrei os
> > > > módulos do Adriano Ferreira, que parecem mais enxutos e podem ser
> > > > vistos/usados em:
> > > >
> http://search.cpan.org/src/FERREIRA/Business-BR-Ids-0.00_16/lib/Business/BR/CPF.pm
> > > >
> http://search.cpan.org/~ferreira/Business-BR-Ids-0.00_16/lib/Business/BR/CNPJ.pm
> > >
> > > Bem, o código para verificar se um CNPJ é válido no Business::BR::CNPJ é
> > >
> > > sub test_cnpj {
> > >   my $cnpj = canon_cnpj shift;
> > >   return undef if length $cnpj != 14;
> > >   my @cnpj = split '', $cnpj;
> > >   my $s1 = _dot([5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0], \@cnpj) %
> 11;
> > >   my $s2 = _dot([6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2, 1], \@cnpj) %
> 11;
> > >   unless ($s1==0 || $s1==1 && $cnpj[12]==0) {
> > >     return 0;
> > >   }
> > >   return ($s2==0 || $s2==1 && $cnpj[13]==0) ? 1 : 0;
> > > }
> > >
> > > que usa "canon_cnpj" para permitir usar CNPJs formatados
> > > "11.111.111/0001-29" ou não e "_dot" para calcular a soma ponderada. O
> > > módulo de CPF é análogo.
> > >
> > > O resto do código dos módulos faz um pouco mais do que este teste de
> > > dígitos de verificação.
> > >
> > > Mais importante que o tamanho do código é a facilidade do uso. Eu
> > > particularmente gosto de usar a interface oferecida por
> > > Business::BR::Ids onde você pode testar CNPJs, CPFs, números de PIS e
> > > algumas inscrições estaduais com um código como:
> > >
> > >      use Business::BR::Ids qw(test_id);
> > >
> > >      $ok = test_id( 'cnpj', '28.282.192/0001-23');
> > >      $ok = test_id( 'cpf', ' 28.818.188-00' );
> > >      $ok = test_id( 'pis', '19.2992.2920-00');
> > >      $ok = test_id( 'ie', 'PR', '82902020802');
> > >
> > >
> > > >
> > > > e o código em Java segue abaixo:
> > > > -----------8<-----------
> > > >  public class CNP {
> > > >     private static final int[] pesoCPF = {11, 10, 9, 8, 7, 6, 5, 4, 3,
> 2};
> > > >     private static final int[] pesoCNPJ = {6, 5, 4, 3, 2, 9, 8, 7, 6,
> 5, 4,
> > > > 3, 2};
> > > >
> > > >     private static int calcularDigito(String str, int[] peso) {
> > > >        int soma = 0;
> > > >        for (int indice=str.length()-1, digito; indice >= 0; indice-- )
> {
> > > >           digito = Integer.parseInt(str.substring(indice,indice+1));
> > > >           soma += digito*peso[peso.length-str.length()+indice];
> > > >        }
> > > >        soma = 11 - soma % 11;
> > > >        return soma > 9 ? 0 : soma;
> > > >     }
> > > >
> > > >     public static boolean isValidCPF(String cpf) {
> > > >        if ((cpf==null) || (cpf.length()!=11)) return false;
> > > >
> > > >        Integer digito1 = calcularDigito(cpf.substring(0,9), pesoCPF);
> > > >        Integer digito2 = calcularDigito(cpf.substring(0,9) + digito1,
> > > > pesoCPF);
> > > >        return cpf.equals(cpf.substring(0,9) + digito1.toString() +
> > > > digito2.toString());
> > > >     }
> > > >
> > > >     public static boolean isValidCNPJ(String cnpj) {
> > > >        if ((cnpj==null)||( cnpj.length()!=14)) return false;
> > > >
> > > >        Integer digito1 = calcularDigito(cnpj.substring(0,12),
> pesoCNPJ);
> > > >        Integer digito2 = calcularDigito(cnpj.substring(0,12) +
> digito1,
> > > > pesoCNPJ);
> > > >        return cnpj.equals(cnpj.substring(0,12) + digito1.toString() +
> > > > digito2.toString());
> > > >     }
> > > >
> > > >     public static void main(String[] args) {
> > > >        System.out.printf("CPF Valido:%s \n",
> CNP.isValidCPF("01115375502"));
> > > >        System.out.printf("CNPJ Valido:%s \n",
> > > > CNP.isValidCNPJ("13642634756318"));
> > > >     }
> > > >  }
> > > > ------------8<-----------------
> > > >
> > > > _______________________________________________
> > > > Rio-pm mailing list
> > > > Rio-pm at pm.org
> > > > http://mail.pm.org/mailman/listinfo/rio-pm
> > > >
> > >
> > _______________________________________________
> > Rio-pm mailing list
> > Rio-pm at pm.org
> > http://mail.pm.org/mailman/listinfo/rio-pm
> >
>
>
> _______________________________________________
> Rio-pm mailing list
> Rio-pm at pm.org
> http://mail.pm.org/mailman/listinfo/rio-pm
>


Mais detalhes sobre a lista de discussão Rio-pm