← 中文资源

简体中文版本

基于 Mod-97 的 IBAN 校验

规范化国际银行账号,按国家长度与 ISO 7064 Mod-97 校验位验证 IBAN 是否有效。

阅读英文原文

功能说明

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;
}