Rumah > Java > javaTutorial > Menyahmisti Algoritma Digit Semak CPF dan CNPJ: Pendekatan yang Jelas dan Ringkas

Menyahmisti Algoritma Digit Semak CPF dan CNPJ: Pendekatan yang Jelas dan Ringkas

PHPz
Lepaskan: 2024-09-03 12:32:03
asal
693 orang telah melayarinya

Demystifying CPF and CNPJ Check Digit Algorithms: A Clear and Concise Approach

Saya teringat dengan jelas pertemuan pertama saya dengan algoritma pengesahan CPF (Brazillian ID) semasa pengajian saya yang belum lulus. Semasa memohon latihan di Institut Sains Tepat di UFMG, Universiti Persekutuan Minas Gerais, kami diminta menulis kod Java, dengan tangan, untuk mengesahkan digit semakan CPF selepas penjelasan ringkas tentang algoritma.

Sejak itu, saya telah menemui masalah ini beberapa kali dalam konteks profesional yang berbeza, sering mengambil jalan keluar untuk menyalin penyelesaian daripada Internet dan menambah beberapa ujian unit. Walau bagaimanapun, setiap kali, saya terkejut dengan isu yang berulang dalam penyelesaian ini. Mereka cenderung lebih berakar dalam paradigma imperatif daripada pendekatan berorientasikan objek yang dijangkakan untuk kod Java. Tetapi, apa yang lebih mengganggu saya, beban kognitif yang tinggi yang dikenakan oleh pelaksanaan ini menjadi tidak praktikal untuk dibaca dan memahami maksud kod tersebut.

Pemaju yang berminat yang masih belum perlu melaksanakan kod ini boleh mencari penyelesaian dengan mudah dalam mana-mana bahasa pengaturcaraan. Walau bagaimanapun, kesemuanya cenderung untuk dipersembahkan dengan cara yang sama: replikasi naif penjelasan tentang cara digit semakan CPF dilaksanakan. Nampaknya hanya sedikit orang yang meluangkan masa untuk memahami alasan di sebalik pendekatan ini.

Masalah perlanggaran

Dalam pembangunan perisian, konsep pengelakan perlanggaran sering ditemui dalam algoritma kod cincang, terutamanya dengan penggunaan modulus nombor perdana. Digit semakan dalam CPF (ID Brazil) dan CNPJ (ID syarikat Brazil) berfungsi sama, bercampur untuk mengelakkan perlanggaran. Ini memastikan penjumlahan mudah digit tidak tersilap mengesahkan entri yang salah, kerana gabungan berbilang boleh menghasilkan jumlah yang sama.

Untuk mengurangkan perkara ini, amalan biasa adalah menggunakan jumlah wajaran, mengalikan setiap digit dengan faktor tertentu. Anda boleh menganggap ini sebagai menyebarkan digit di sepanjang garis; pendaraban menjadikannya kurang berkemungkinan untuk berbilang digit mendarat dalam kedudukan yang sama. Oleh itu, masuk akal bahawa kedudukan digit dalam nombor menentukan beratnya.

Untuk meningkatkan lagi kebolehpercayaan dan meminimumkan risiko perlanggaran, jumlah diambil modulo 11, dan keputusan ini ditolak daripada nombor perdana yang sama. Untuk memastikan digit semakan kekal satu digit, keputusan 10 dan 11 ditukar kepada 0.

Beban kognitif

Algoritma yang digunakan untuk mengira digit semakan untuk CPF dan CNPJ mungkin sukar difahami. Walaupun motivasi keseluruhan di sebalik algoritma mungkin jelas, ia sememangnya mencabar untuk memahami peranan khusus setiap bahagian. Kerumitan ini timbul sebahagiannya kerana pengiraan melibatkan satu siri pengiraan matematik yang sering digabungkan dalam satu kaedah yang besar. Selain itu, pemberat, yang biasanya dibentangkan sebagai tatasusunan yang tidak dapat diterangkan, boleh kelihatan tidak logik.

Untuk mengatasi masalah ini, saya menumpukan pada mengurangkan jumlah kod yang tidak memerlukan penjelasan sendiri. Dengan mematuhi Pengetua Tanggungjawab Tunggal ("S" dalam SOLID), saya berusaha untuk mencipta kaedah yang lebih mudah dan boleh difahami. Saya juga berusaha untuk mentakrifkan konsep-konsep utama melalui nama pembolehubah yang bermakna, bertujuan untuk mewujudkan bahasa di mana-mana dalam pangkalan kod. Dengan pendekatan ini, saya berusaha untuk mengenal pasti perkara yang membezakan kaedah yang digunakan untuk digit semakan CPF daripada yang digunakan untuk CNPJ, kerana perisian yang memerlukan satu sering memerlukan yang lain. Fungsi teras kod ditunjukkan di bawah, juga, untuk paparan lanjut, termasuk kod lengkap dan ujian unit yang berkaitan, sila lawati repositori GitHub saya.

  private String getCheckDigits(String document, int maxWeight) {
    final int lengthWithoutCheckDigits = getBaseDigitsLength(document);

    int firstWeightedSum = 0;
    int secondWeightedSum = 0;
    for (int i = 0; i < lengthWithoutCheckDigits; i++) {
      final int digit = Character.getNumericValue(document.charAt(i));
      final int maxIndex = lengthWithoutCheckDigits - 1;
      final int reverseIndex = maxIndex - i;
      firstWeightedSum += digit * calculateWeight(reverseIndex, maxWeight);
      // Index is incremented, starting from 3, skipping first check digit.
      // The first part will be added later as the calculated first check digit times its corresponding weight.
      secondWeightedSum += digit * calculateWeight(reverseIndex + 1, maxWeight);
    }

    final int firstDigit = getCheckDigit(firstWeightedSum);
    // Add the first part as the first check digit times the first weight.
    secondWeightedSum += MIN_WEIGHT * firstDigit;
    final int secondDigit = getCheckDigit(secondWeightedSum);

    return String.valueOf(firstDigit) + secondDigit;
  }

  private int calculateWeight(int complementaryIndex, int maxWeight) {
    return complementaryIndex % (maxWeight - 1) + MIN_WEIGHT;
  }

  private int getCheckDigit(int weightedSum) {
    final var checkDigit = enhanceCollisionAvoidance(weightedSum);
    return checkDigit > 9 ? 0 : checkDigit;
  }

  private int enhanceCollisionAvoidance(int weightedSum) {
    final var weightSumLimit = 11;
    return weightSumLimit - weightedSum % weightSumLimit;
  }
Salin selepas log masuk

Bandingkan hasil yang mengira digit semakan untuk CNPJ dan CPF dengan penyelesaian tipikal yang terdapat dalam Internet:

public class ValidaCNPJ {

  public static boolean isCNPJ(String CNPJ) {
// considera-se erro CNPJ's formados por uma sequencia de numeros iguais
    if (CNPJ.equals("00000000000000") || CNPJ.equals("11111111111111") ||
        CNPJ.equals("22222222222222") || CNPJ.equals("33333333333333") ||
        CNPJ.equals("44444444444444") || CNPJ.equals("55555555555555") ||
        CNPJ.equals("66666666666666") || CNPJ.equals("77777777777777") ||
        CNPJ.equals("88888888888888") || CNPJ.equals("99999999999999") ||
       (CNPJ.length() != 14))
       return(false);

    char dig13, dig14;
    int sm, i, r, num, peso;

// "try" - protege o código para eventuais erros de conversao de tipo (int)
    try {
// Calculo do 1o. Digito Verificador
      sm = 0;
      peso = 2;
      for (i=11; i>=0; i--) {
// converte o i-ésimo caractere do CNPJ em um número:
// por exemplo, transforma o caractere '0' no inteiro 0
// (48 eh a posição de '0' na tabela ASCII)
        num = (int)(CNPJ.charAt(i) - 48);
        sm = sm + (num * peso);
        peso = peso + 1;
        if (peso == 10)
           peso = 2;
      }

      r = sm % 11;
      if ((r == 0) || (r == 1))
         dig13 = '0';
      else dig13 = (char)((11-r) + 48);

// Calculo do 2o. Digito Verificador
      sm = 0;
      peso = 2;
      for (i=12; i>=0; i--) {
        num = (int)(CNPJ.charAt(i)- 48);
        sm = sm + (num * peso);
        peso = peso + 1;
        if (peso == 10)
           peso = 2;
      }

      r = sm % 11;
      if ((r == 0) || (r == 1))
         dig14 = '0';
      else dig14 = (char)((11-r) + 48);

// Verifica se os dígitos calculados conferem com os dígitos informados.
      if ((dig13 == CNPJ.charAt(12)) && (dig14 == CNPJ.charAt(13)))
         return(true);
      else return(false);
    } catch (InputMismatchException erro) {
        return(false);
    }
  }
}
Salin selepas log masuk

Sekeping kod ini hanya untuk CNPJ!

Kesimpulan

Walaupun kod hasil mungkin kelihatan agak bertele-tele, penekanan saya pada kejelasan dan penjelasan sendiri membawa kepada hasil yang saya berpuas hati. Kod ini direka bentuk untuk menjadi lebih intuitif, menawarkan keyakinan yang lebih besar dalam ketepatannya dan, juga, kebanyakan fungsi teras boleh dilihat tanpa menatal ke bawah halaman.

Saya mengalu-alukan sebarang cadangan untuk penambahbaikan selanjutnya, jadi sila berasa bebas untuk berkongsi maklum balas anda.

Atas ialah kandungan terperinci Menyahmisti Algoritma Digit Semak CPF dan CNPJ: Pendekatan yang Jelas dan Ringkas. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:dev.to
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan