quarta-feira, 18 de julho de 2012

Algoritmo do CPF

Achei interessante o algoritmo dos dígitos verificadores do CPF (Cadastro de Pessoa Física) e apresento o código-fonte em C++.

Para gerar o binário é necessário 3 arquivos:

  1. Definição da classe
  2. Definições das funções-membros da classe
  3. Programa driver

1. Definição da classe

$ cat Cpfnum.h

#ifndef CPFNUM_H 
#define CPFNUM_H 

class Cpfnum { 
public: 
    Cpfnum(); 
    Cpfnum(const Cpfnum& orig); 
    virtual ~Cpfnum();
    int PrimeiroDigito(int, int, int, int, int ,int ,int, int, int);
    int SegundoDigito (int, int, int, int, int ,int ,int, int, int, int);
private:


#endif /* CPFNUM_H */

2. Definições das funções-membros da classe

$ cat Cpfnum.cpp

#include <iostream>
using std::cout;
using std::cin;
using std::endl;
#include <cstring>
using std::string;

#include "Cpfnum.h"

Cpfnum::Cpfnum() {
}

Cpfnum::Cpfnum(const Cpfnum& orig) {
}

Cpfnum::~Cpfnum() {
}

int Cpfnum::PrimeiroDigito(int v1,int v2,int v3,int v4,int v5,int v6,int v7,int v8,int v9)
{
  int m1, m2, m3, m4, m5, m6, m7, m8, m9; // multiplicado    
  int soma, resto, v10; 
  
  m1=v1*10;
  m2=v2*9;
  m3=v3*8;
  m4=v4*7;
  m5=v5*6;
  m6=v6*5;
  m7=v7*4;
  m8=v8*3;
  m9=v9*2;
  
// somando m1 a m9
  soma=m1+m2+m3+m4+m5+m6+m7+m8+m9;

// obtendo o 1° dígito verificador: divisão da soma por 11 e o resto é o 1° dígito verificador
    resto=soma%11;
    if (resto < 2)
      v10=0;
    else
      v10=11-resto;
    
    return v10;
}

int Cpfnum::SegundoDigito (int v1,int v2,int v3,int v4,int v5,int v6,int v7,int v8,int v9, int v10)
{
  int m1, m2, m3, m4, m5, m6, m7, m8, m9, m10; // multiplicado
  int soma, resto, v11;

// novos valores multiplicados após encontrar o 1° dígito verificador
   m1=v1*11;
   m2=v2*10;
   m3=v3*9;
   m4=v4*8;
   m5=v5*7;
   m6=v6*6;
   m7=v7*5;
   m8=v8*4;
   m9=v9*3;
   m10=v10*2;

// somando m1 a m10
    soma=m1+m2+m3+m4+m5+m6+m7+m8+m9+m10;

// divisão da soma por 11. Aplica-se regra do resto para encontrar o 2° dígito verificador
    resto=soma%11;
    if (resto < 2)
      v11=0;
    else
      v11=11-resto;

    return v11;
}

3. Programa driver

$ cat main.cpp

#include <iostream>
using std::cout;
using std::cin;
using std::endl;
#include <cstring>
using std::string;
#include <sstream>
using std::stringstream;
#include <cstdlib>

#include "Cpfnum.h"

//using namespace std;

int main(int argc, char** argv) {
    
  string mystring;
  string sv1, sv2, sv3, sv4, sv5, sv6, sv7, sv8, sv9, sv10, sv11; // sv10 = 1° dígito verificador e sv11 = 2° dígito verificador
  int v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11;  // valor
  int pdv, sdv; // primeiro e segundo digito verificador

  cout << "Entre com o número do CPF: ";
  cin >> mystring;

  sv1=mystring[0];
  sv2=mystring[1];
  sv3=mystring[2];
  sv4=mystring[3];
  sv5=mystring[4];
  sv6=mystring[5];
  sv7=mystring[6];
  sv8=mystring[7];
  sv9=mystring[8];

  stringstream(sv1) >> v1;
  stringstream(sv2) >> v2;
  stringstream(sv3) >> v3;
  stringstream(sv4) >> v4;
  stringstream(sv5) >> v5;
  stringstream(sv6) >> v6;
  stringstream(sv7) >> v7;
  stringstream(sv8) >> v8;
  stringstream(sv9) >> v9;

  if (mystring.length() < 9 || mystring.length() == 10 || mystring.length() > 11)
    cout << "Você digitou " << mystring.length() << " caracteres. Digite 9 ou 11." << endl;

  Cpfnum myCpfnum;
  myCpfnum.PrimeiroDigito(v1, v2, v3, v4, v5, v6, v7, v8, v9);
  myCpfnum.SegundoDigito(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10);
  
  if (mystring.length() == 9)
  {
    v10=myCpfnum.PrimeiroDigito (v1, v2, v3, v4, v5, v6, v7, v8, v9);
    v11=myCpfnum.SegundoDigito (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10);
    cout << v1 << v2 << v3 << v4 << v5 << v6 << v7 << v8 << v9 << "-" << v10 << v11 << endl;
  }
  
  if (mystring.length() == 11)
  {
    pdv=myCpfnum.PrimeiroDigito (v1, v2, v3, v4, v5, v6, v7, v8, v9);
    sdv=myCpfnum.SegundoDigito (v1, v2, v3, v4, v5, v6, v7, v8, v9, pdv);

    sv10=mystring[9];
    sv11=mystring[10];
    stringstream(sv10) >> v10;  
    stringstream(sv11) >> v11;

    if ( (v10 == pdv ) && (v11 == sdv ) )
      cout << "CPF válido!" << endl;
    else
      cout << "CPF inválido" << endl;
  }
  
  return 0;
}

Considerações finais:

Uma IDE (Integrated Development Environment) faz muita diferença no desenvolvimento. Meus primeiros programas foram elaborados com o Anjuta, mas passei a usar o NetBeans.

O Anjuta cria as classes sem muitas instruções (virtual) o que considero bom para começar o contato com C++. No entanto, nada impede de iniciar com NetBeans e ignorar algumas funções-membros.

As IDEs vem com as configurações que buscam o compilador para gerar o binário. Caso prefira colar os respectivos conteúdo nos três arquivos com os nomes sugeridos, a linha de comando é:

$ g++ Cpfnum.cpp main.cpp -o cpf.out -ansi

E para escrever este texto usei o BlueFish. Claro que não deixei de usar o VIM, principalmente porque um recurso essencial como colar em colunas só encontro nele.