JS实现CNPJ字母格式校验:别让旧正则搞崩你的系统
很多写过巴西业务代码的开发者可能还没意识到,CNPJ(巴西企业税号)现在支持字母了。如果你还在用
下一篇
强类型防坑:用 TypeScript 降低 OWASP 风险 →
^\d{14}$ 这种纯数字正则,或者数据库字段开了 BIGINT,那么新格式的 12.ABC.345/01DE-35 进来时,你的系统大概率会直接报错或静默损坏。最坑的点在于,虽然前12位允许 0-9 和 A-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-alfanumericoconst 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 和正则校验位,避免上线后才发现新公司无法注册。