Maison > Java > javaDidacticiel > le corps du texte

Démystifier les algorithmes de contrôle CPF et CNPJ : une approche claire et concise

PHPz
Libérer: 2024-09-03 12:32:03
original
610 Les gens l'ont consulté

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

Je me souviens très bien de ma première rencontre avec l'algorithme de validation CPF (Brazillian ID) au cours de mes études de premier cycle. Alors que nous postulions pour un stage à l'Institut des Sciences Exactes de l'UFMG, l'Université Fédérale du Minas Gerais, on nous a demandé d'écrire à la main un code Java pour valider les chiffres de contrôle du CPF après une brève explication de l'algorithme.

Depuis, j'ai rencontré ce problème à plusieurs reprises dans différents contextes professionnels, recourant souvent à la copie de solutions depuis Internet et à l'ajout de quelques tests unitaires. Cependant, à chaque fois, je suis frappé par les problèmes récurrents de ces solutions. Ils ont tendance à être plus ancrés dans un paradigme impératif que dans l'approche orientée objet attendue pour les codes Java. Mais ce qui me dérange encore plus, c'est la charge cognitive élevée imposée par ces implémentations qui s'avère peu pratique pour lire et comprendre l'intention du code.

Un développeur intéressé qui n'a pas encore eu besoin d'implémenter ce code peut facilement trouver des solutions dans n'importe quel langage de programmation. Cependant, ils ont tous tendance à être présentés de la même manière : une réplication naïve de l’explication de la manière dont les chiffres de contrôle du CPF sont mis en œuvre. Il semble que peu de gens prennent le temps de comprendre le raisonnement qui se cache derrière cette démarche.

Le problème des collisions

Dans le développement de logiciels, le concept d'évitement de collision est souvent rencontré dans les algorithmes de hash code, notamment avec l'utilisation du module des nombres premiers. Les chiffres de contrôle du CPF (ID brésilien) et du CNPJ (ID de l'entreprise brésilienne) fonctionnent de la même manière, visant à éviter les collisions. Cela garantit qu'une simple somme de chiffres ne valide pas par erreur des entrées incorrectes, car plusieurs combinaisons peuvent produire la même somme.

Pour atténuer cela, une pratique courante consiste à appliquer des sommes pondérées, en multipliant chaque chiffre par un facteur spécifique. Vous pouvez considérer cela comme une répartition des chiffres le long d'une ligne ; la multiplication rend moins probable que plusieurs chiffres atterrissent dans la même position. Il est donc logique que la position du chiffre dans le nombre détermine son poids.

Pour améliorer encore la fiabilité et minimiser les risques de collisions, la somme est prise modulo 11, et ce résultat est soustrait du même nombre premier. Pour garantir que le chiffre de contrôle reste un seul chiffre, les résultats de 10 et 11 sont convertis en 0.

La charge cognitive

L'algorithme utilisé pour calculer les chiffres de contrôle du CPF et du CNPJ peut être difficile à comprendre. Même si la motivation globale derrière l’algorithme peut être claire, il est souvent difficile de saisir le rôle spécifique de chaque élément. Cette complexité vient en partie du fait que le calcul implique une série de calculs mathématiques qui sont souvent regroupés dans une seule et grande méthode. De plus, les poids, généralement présentés comme un tableau inexplicable, peuvent sembler illogiques.

Pour lutter contre cela, je me concentre sur la réduction de la quantité de code qui manque d'explication. En adhérant au principe de responsabilité unique (le « S » dans SOLID), je m'efforce de créer des méthodes plus simples et plus compréhensibles. Je m'efforce également de définir des concepts clés à travers des noms de variables significatifs, dans le but d'établir un langage omniprésent au sein de la base de code. Avec cette approche, j'ai cherché à identifier ce qui différencie la méthode utilisée pour les chiffres de contrôle CPF de celle utilisée pour CNPJ, car les logiciels qui nécessitent l'un ont souvent besoin de l'autre. La fonctionnalité principale du code est présentée ci-dessous. Pour une vue plus approfondie, y compris le code complet et les tests unitaires associés, veuillez visiter mon référentiel GitHub.

  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;
  }
Copier après la connexion

Comparez le résultat qui calcule les chiffres de contrôle pour CNPJ et CPF avec la solution typique trouvée sur 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);
    }
  }
}
Copier après la connexion

Ce morceau de code est réservé à CNPJ !

Conclusion

Bien que le code de résultat puisse paraître quelque peu verbeux, l'accent mis sur la clarté et l'auto-explication a conduit à un résultat dont je suis satisfait. Le code est conçu pour être plus intuitif, offrant une plus grande confiance dans son exactitude et, également, la plupart des fonctionnalités de base sont visibles sans faire défiler la page.

J'apprécie toutes les suggestions d'amélioration, alors n'hésitez pas à partager vos commentaires.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!