我清楚地记得我在本科学习期间第一次接触CPF(巴西ID)验证算法。申请米纳斯吉拉斯州联邦大学 ufmg 在精确的科学研究所实习期间,我们被要求手写一段 java 简单解释算法后验证代码 cpf 校验位。
从那以后,我在不同的专业环境中多次遇到这个问题,经常求助于从互联网上复制解决方案,并添加一些单元测试。然而,每次,我都对这些解决方案中反复出现的问题感到震惊。它们往往更多地植根于命令范例,而不是预期的 java 面向对象的代码方法。但更让我困扰的是,这些实现带来的高认知负荷使得阅读和理解代码的意图变得不切实际。
对该代码不感兴趣的开发人员可以很容易地找到任何编程语言的解决方案。然而,它们都倾向于以同样的方式呈现:是的 cpf 简单复制如何实现验证位的解释。似乎很少有人花时间去理解这种方法背后的原因。
碰撞问题哈希码算法在软件开发中经常遇到碰撞避免的概念,尤其是在使用素数模的情况下。 cpf(巴西id)类似于cnpj(巴西id)中的验证位功能,重点是避免冲突。这确保了简单的数字求和不会错误地验证不正确的项目,因为各种组合可以产生相同的总和。
为了缓解这种情况,常见的方法是应用加权和将每个数字乘以一个特定的因素。您可以将其视为沿一条线扩展数字;乘法使多个数字不太可能出现在同一位置。因此,数字在数字中的位置决定其权重是合理的。
为了进一步提高可靠性,最大限度地降低碰撞风险,总和 11 它是模具,然后从相同的素数中减去结果。为了确保验证位仍然是个位数,10 和 11 结果将转化为 0。
认知负荷用于计算 cpf 和 cnpj 验证位置的算法可能很难理解。虽然算法背后的整体动机可能很清楚,但掌握每个部分的具体功能通常是具有挑战性的。这种复杂性的部分原因是计算涉及一系列数学计算,通常集中在单一的大型方法中。此外,以莫名其妙的数组形式呈现的权重可能是不合逻辑的。
为了解决这个问题,我专注于减少缺乏自我解释的代码。坚持单一职责的原则(solid 中的“s),我努力创造一种更简单、更容易理解的方法。我还试图通过有意义的变量名来定义关键概念,旨在在代码库中建立一种常见的语言。通过这种方法,我试图找出它是用来做的 cpf 验证位置的方法及用途 cnpj 由于需要一种方法的软件通常需要另一种方法,因此方法的区别。代码的核心功能如下所示。此外,还需要进一步查看,包括完整的代码和相关单元测试。请访问我 github 存储库。
private string getcheckdigits(string document, int maxweight) { final int lengthwithoutcheckdigits = getbasedigitslength(document); int firstweightedsum = 0; int secondweightedsum = 0; for (int i = 0; i 9 ? 0 : checkdigit; } private int enhancecollisionavoidance(int weightedsum) { final var weightsumlimit = 11; return weightsumlimit - weightedsum % weightsumlimit; }
将cnpj和cpf的校准计算结果与网上找到的典型解决方案进行比较:
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); } } }
本代码仅供cnpj使用!
结论虽然结果代码可能看起来有点冗长,但我对清晰度和自我解释的强调导致了我满意的结果。代码设计更直观,对其正确性更有信心,大多数核心功能不需要向下滚动页面。
我欢迎任何进一步改进的建议,所以请随时分享您的反馈。
以上就是揭秘 CPF 和 CNPJ 验证算法:方法的详细内容清晰简洁,请关注图灵教育的其他相关文章!