JS实现CNPJ字母格式校验:别让旧正则搞崩你的系统

完美主义技术宅 专家 7小时前 更新于 2026年7月26日 269 浏览 4 点赞 约 1 分钟

很多写过巴西业务代码的开发者可能还没意识到,CNPJ(巴西企业税号)现在支持字母了。如果你还在用 ^\d{14}$ 这种纯数字正则,或者数据库字段开了 BIGINT,那么新格式的 12.ABC.345/01DE-35 进来时,你的系统大概率会直接报错或静默损坏。

最坑的点在于,虽然前12位允许 0-9A-Z,但最后两位校验码依然是纯数字。校验算法虽然还是模11,但计算权重的取值变了:字符需要转换为 ASCII 码减去 48(数字 0-9 依然是 0-9,而字母 A-Z 对应 17-42)。

这里分享一个精简的实战实现,可以直接拿去用:

function checkDigits(base12) {
  const W1 = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
  const W2 = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
  
  // 核心转换逻辑:ASCII - 48
  const val = (ch) => ch.charCodeAt(0) - 48;

  const calculateDv = (chars, weights) => {
    const sum = chars.reduce((acc, ch, i) => acc + val(ch) * weights[i], 0);
    const rest = sum % 11;
    return rest < 2 ? 0 : 11 - rest;
  };

  const c = base12.split("");
  const dv1 = calculateDv(c, W1);
  const dv2 = calculateDv([...c, String(dv1)], W2);
  return `${dv1}${dv2}`;
}

// 测试官方示例: 12ABC34501DE -> 校验码应为 35
console.log(checkDigits("12ABC34501DE"));

对于需要快速部署到生产环境的项目,建议直接上成熟的 npm 包,省去处理掩码和边缘情况的麻烦:

npm install valida-cnpj-alfanumerico

const CNPJ = require("valida-cnpj-alfanumerico");

// 直接校验带格式的字符串
if (CNPJ.isValid("12.ABC.345/01DE-35")) {
  console.log("Valid CNPJ");
}

// 生成测试数据给 QA 跑用例
const testData = CNPJ.generate({ alphanumeric: true, masked: true });

这次升级对老系统的冲击很大,尤其是那些习惯用 parseInt() 处理税号的逻辑。建议在 PR 阶段就用工具扫描一遍 codebase,重点检查数据库 Schema 和正则校验位,避免上线后才发现新公司无法注册。

AI编程AI编程实战programmingjavascriptTutorial

全部回复 (3)

大Tom在路上 初级 13小时前
建议入库前先统一转大写,省得后面查询的时候对不上。
0 回复
产品经理大熊 高级 13小时前
记得处理下大小写统一,不然正则匹配很容易漏掉。
0 回复
养生全栈 中级 13小时前
我之前就被这坑过,当时生产环境直接报了格式错误。
0 回复

发表回复

支持 Markdown 格式