功能说明
该示例用 Luhn 算法校验银行卡号这类数字串。它先去掉空格与连字符,要求长度为 12 到 19 位且全为数字,再从右往左对每隔一位的数字翻倍并求和,总和能被 10 整除即通过。另一个函数可以在已知前若干位时计算最后一位校验码,适合表单实时提示。
关键代码
normalize 只允许字符串或数字输入,非数字字符会抛错,避免把任意文本静默当成空串。luhnSum 从最右位开始,用布尔变量控制是否翻倍,翻倍后大于 9 就减 9,等价于各位数字相加。cardCheckDigit 在部分号码后补 0 再求和,用 10 减去余数再取模得到校验位。
使用注意
Luhn 只能发现单一位错误和大部分相邻换位错误,不能证明卡号真实存在,也不能替代发卡行网络校验。它不校验卡组织、有效期或 CVV,更不应记录完整卡号。测试卡号可以公开使用,生产日志必须脱敏。长度范围可按业务调整,但不要放宽到空串或一位数字。
验证方式
断言 4242 4242 4242 4242 通过,改掉最后一位后失败。用前十五位 424242424242424 计算校验位应得到 2,拼回后再次通过。测试带空格、连字符与纯数字输入结果一致。传入字母、空串、过短或过长数字分别断言抛错或返回 false。
代码示例
export function isValidCardNumber(input) {
const digits = normalize(input);
if (digits.length < 12 || digits.length > 19) return false;
return luhnSum(digits) % 10 === 0;
}
export function cardCheckDigit(partial) {
const digits = normalize(partial);
if (digits.length < 11 || digits.length > 18) {
throw new RangeError("partial number must contain 11 to 18 digits");
}
const remainder = luhnSum(`${digits}0`) % 10;
return String((10 - remainder) % 10);
}
function normalize(input) {
if (typeof input !== "string" && typeof input !== "number") {
throw new TypeError("card number must be a string or number");
}
const value = String(input).replace(/[\s-]/g, "");
if (!/^\d*$/.test(value)) {
throw new Error("card number may only contain digits, spaces and hyphens");
}
return value;
}
function luhnSum(digits) {
let sum = 0;
let double = false;
for (let index = digits.length - 1; index >= 0; index -= 1) {
let value = Number(digits[index]);
if (double) {
value *= 2;
if (value > 9) value -= 9;
}
sum += value;
double = !double;
}
return sum;
}
const sample = "4242 4242 4242 4242";
console.log(isValidCardNumber(sample));
console.log(isValidCardNumber("4242424242424241"));
console.log(cardCheckDigit("424242424242424"));