功能说明
normalizeIban 去除空格和连字符并转为大写,isValidIban 先检查国家代码、校验位与字符集,再按国家长度表和 Mod-97 算法验证。IBAN 广泛用于欧元区及其他地区的跨境转账,前端表单与后台批量导入都应在入库前校验,避免因一位数字错误导致退款或人工处理。
关键代码
规范化后先用正则确认两位国家字母、两位数字校验位和十一位到三十位字母数字。国家长度表覆盖常见国家,长度不符直接返回 false。校验时把前四位移到末尾,把字母转换为两位数字,A 为 10、B 为 11,依此类推。逐位累加余数而不是构造超大整数,避免精度问题,最终余数为 1 即通过。
使用注意
Mod-97 只能证明号码结构自洽,不能证明账户真实存在,正式转账仍需银行或支付服务商验证。长度表需要随 IBAN 注册表更新,新增国家应及时维护。输入中的空格与连字符会被忽略,但其他分隔符不会。不要把格式化后的展示值直接入库,统一存规范化形式。校验失败应给出中性提示,避免泄露账户信息。
验证方式
用公开的合法 IBAN 样例测试德国、法国、英国与荷兰号码,包含带空格和连字符的写法。测试交换两位数字、改动校验位、长度错误、未知国家、小写输入与空字符串。确认 normalizeIban 输出大写且无分隔符,并验证非法字符与超长输入返回 false 而不是抛错。
代码示例
const IBAN_LENGTHS: Record<string, number> = {
AL: 28, AD: 24, AT: 20, AZ: 28, BH: 22, BE: 16, BA: 20, BR: 29,
BG: 22, CR: 22, HR: 21, CY: 28, CZ: 24, DK: 18, DO: 28, EE: 20,
FO: 18, FI: 18, FR: 27, GE: 22, DE: 22, GI: 23, GR: 27, GL: 18,
GT: 28, HU: 28, IS: 26, IE: 22, IL: 23, IT: 27, JO: 30, KZ: 20,
XK: 20, KW: 30, LV: 21, LB: 28, LI: 21, LT: 20, LU: 20, MK: 19,
MT: 31, MR: 27, MU: 30, MD: 24, MC: 27, ME: 22, NL: 18, NO: 15,
PK: 24, PS: 29, PL: 28, PT: 25, QA: 29, RO: 24, LC: 32, SM: 27,
ST: 25, SA: 24, RS: 22, SC: 31, SK: 24, SI: 19, ES: 24, SE: 24,
CH: 21, TL: 23, TN: 24, TR: 26, UA: 29, AE: 23, GB: 22, VA: 22,
VG: 24,
};
export function normalizeIban(input: string): string {
return input.replace(/[\s-]/g, "").toUpperCase();
}
export function isValidIban(input: string): boolean {
const iban = normalizeIban(input);
if (!/^[A-Z]{2}\d{2}[A-Z0-9]{11,30}$/.test(iban)) return false;
const country = iban.slice(0, 2);
if (IBAN_LENGTHS[country] !== iban.length) return false;
const rearranged = iban.slice(4) + iban.slice(0, 4);
let remainder = 0;
for (const character of rearranged) {
const digits = /\d/.test(character)
? character
: String(character.charCodeAt(0) - 55);
for (const digit of digits) {
remainder = (remainder * 10 + Number(digit)) % 97;
}
}
return remainder === 1;
}