解密 CNPJ 算法

CNPJ 由十四位数字组成,分为三个块:

  • 第一个,代表注册号本身;
  • 第二个,位于斜线之后,代表矩阵或分支的唯一代码;
  • 第三个,由称为校验位(DV)的最后两个值表示。

校验位 (DV) 从前十二位创建。使用 11 除法模块分两步完成计算。

为了举例说明这个过程并使解释更容易,让我们计算一个假设的 CNPJ 的校验位,例如 11.444.777/0001-XX。

计算第一个校验位

第一个数字使用以下算法计算。

1)将权重5,4,3,2,9,8,7,6,5,4,3,2从左到右依次排列在一个框架中的前12位,如下图:

1 1 4 4 4 7 7 7 0 0 0 1
5 4 3 9 8 7 6 5 4 3

2)将每一列的值相乘:

1 1 4 4 4 7 7 7 0 0 0 1
5 4 3 9 8 7 6 5 4 3
5 4 12 8 36 56 49 42 0 0 0

3)计算结果之和 (5+4+...+0+2) = 214

4)得到的结果(214)将除以11。仅将整数值视为商,除法的余数将负责计算第一个校验位。

让我们继续:214 除以 11 我们得到 19 作为商,5 作为除法的余数。如果除法的余数小于 2,我们的第一个校验位变为 0(零),否则得到的值从 11 中减去,这就是我们的情况。所以我们的校验位是11-5,也就是6(六)。

因此,我们已经有了 CNPJ 的一部分,检查:11.444.777/ 0001-6 X。

计算第二个校验位

1)对于第二位的计算,将使用已计算的第一个校验位。我们将建立一个与上一个类似的表,只是这次我们将在第二行中使用值 6,5,4,3,2,9,8,7,6,5,4,3, 2 因为我们为这个计算加入了一个数字。看:

1 1 4 4 4 7 7 7 0 0 0 1 6
6 5 4 3 9 8 7 6 5 4 3

2)下一步,我们将按照计算第一个校验位的情况,将每一列的值相乘,并将得到的结果求和:(6+5+... +3+12) = 221。

1 1 4 4 4 7 7 7 0 0 0 1 6
6 5 4 3 9 8 7 6 5 4 3
6 5 16 12 8 63 56 49 0 0 0 3 12

3)我们再次执行模块 11 的计算,我们将总和除以 11 并考虑除法的余数。

让我们继续:230 除以 11 我们得到 20 作为商,10 作为除数的余数。

4)如果除法的余数小于2,则该值自动变为0,否则(如我们的示例)需要从11中减去得到的值以获得校验位,如计算中执行的那样的第一个数字。所以 11-10 = 1是我们的第二个校验位。

我们到了计算的最后,发现我们假设的 CNPJ 的校验位是数字61,所以 CNPJ 看起来像这样:11.444.777/0001-61。

本网站上介绍的cnpj 生成器基于此算法工作。生成有效 CNPJ 的例程最初抽取 9 个数字。第一个校验位被计算并集成到 9 个初始数字中。按照教导继续计算第二个校验位。最后,CNPJ 创建者发出一个有效的 CNPJ 编号。

有效 CPF 的生成以类似的方式工作。如果您有兴趣,请参阅有关cpf 算法的更多信息。

CNPJ算法的实现

function validarCNPJ(cnpj) {

    cnpj = cnpj.replace(/[^\d]+/g,'');

    if(cnpj == '') return false;

    if (cnpj.length != 14)
        return false;

    // Elimina CNPJs invalidos conhecidos
    if (cnpj == "00000000000000" ||
        cnpj == "11111111111111" ||
        cnpj == "22222222222222" ||
        cnpj == "33333333333333" ||
        cnpj == "44444444444444" ||
        cnpj == "55555555555555" ||
        cnpj == "66666666666666" ||
        cnpj == "77777777777777" ||
        cnpj == "88888888888888" ||
        cnpj == "99999999999999")
        return false;

    // Valida DVs
    tamanho = cnpj.length - 2
    numeros = cnpj.substring(0,tamanho);
    digitos = cnpj.substring(tamanho);
    soma = 0;
    pos = tamanho - 7;
    for (i = tamanho; i >= 1; i--) {
      soma += numeros.charAt(tamanho - i) * pos--;
      if (pos < 2)
            pos = 9;
    }
    resultado = soma % 11 < 2 ? 0 : 11 - soma % 11;
    if (resultado != digitos.charAt(0))
        return false;

    tamanho = tamanho + 1;
    numeros = cnpj.substring(0,tamanho);
    soma = 0;
    pos = tamanho - 7;
    for (i = tamanho; i >= 1; i--) {
      soma += numeros.charAt(tamanho - i) * pos--;
      if (pos < 2)
            pos = 9;
    }
    resultado = soma % 11 < 2 ? 0 : 11 - soma % 11;
    if (resultado != digitos.charAt(1))
          return false;

    return true;
}