IBAN 校验位的计算原理

一步步拆解 MOD-97 方法,附一个可以在纸上跟着算的例子和几行代码。

更新于

每个 IBAN 的第 3 和第 4 个字符是校验位。它们根据其余所有字符,用一种名为 MOD 97-10 的方法算出,这种方法由 ISO/IEC 7064 标准定义。您输入 IBAN 时,软件会重新算一遍;如果结果不对,就说明 IBAN 有输入错误。

四步校验一个 IBAN

以德国示例 IBAN DE89 3704 0044 0532 0130 00 为例。

  1. 去掉空格:DE89370400440532013000。
  2. 把前四个字符移到末尾:370400440532013000DE89。
  3. 把每个字母换成两位数字,A = 10,B = 11,依此类推,直到 Z = 35。这里 D 变成 13,E 变成 14:370400440532013000131489。
  4. 用这个数除以 97,取余数。如果余数为 1,这个 IBAN 就是有效的。

在这个例子中,370400440532013000131489 除以 97 的余数正好是 1,所以校验位正确。

计算校验位

为新的 IBAN 生成校验位,步骤相同,只是先用 00 代替校验位:

  1. 写下国家代码,接着写 00 和 BBAN:DE00370400440532013000。
  2. 按上面的方法调整顺序并转换:370400440532013000131400。
  3. 计算它除以 97 的余数,这里是 9。
  4. 用 98 减去余数:98 − 9 = 89。如有需要,在前面补 0 凑足两位(例如 7 写成 07)。

校验位是 89,由此得到 DE89370400440532013000。第 4 步的结果总在 2 到 98 之间,所以有效 IBAN 的校验位永远不会是 00、01 或 99。

处理很长的数字

转换后的数字长度因国家而异:挪威为 17 位,德国为 24 位,含字母的马耳他 IBAN 超过 40 位。大多数都超出普通计算器和 64 位整数(约 19 位)的范围。可以把它拆成几段来算:先取前 9 位数字求余数,把余数写在接下来几位数字的前面,然后重复这个过程:

步骤 数字 除以 97 后的余数
1 370400440 23
2 23 + 5320130 = 235320130 70
3 70 + 0013148 = 700013148 38
4 38 + 9 = 389 1

最终余数是 1,与整个数直接相除的结果相同。

用代码实现同样的校验

JavaScript 版本,每次处理一位数字,因此不需要大数运算:

function isValidIban(input) {
  const iban = input.replace(/\s+/g, '').toUpperCase();
  if (!/^[A-Z]{2}\d{2}[A-Z0-9]{11,30}$/.test(iban)) return false;
  const rearranged = iban.slice(4) + iban.slice(0, 4);
  let remainder = 0;
  for (const ch of rearranged) {
    const value = parseInt(ch, 36); // 0-9 stay digits, A-Z become 10-35
    remainder = (value > 9 ? remainder * 100 : remainder * 10) + value;
    remainder %= 97;
  }
  return remainder === 1;
}

Python 版本,Python 的整数可以任意大:

def is_valid_iban(value: str) -> bool:
    iban = "".join(value.split()).upper()
    if not (iban.isascii() and iban.isalnum() and 15 <= len(iban) <= 34):
        return False
    rearranged = iban[4:] + iban[:4]
    digits = "".join(str(int(ch, 36)) for ch in rearranged)
    return int(digits) % 97 == 1

这些函数只检查结构和校验位。真正的验证程序还要检查该国是否使用 IBAN,以及长度是否与该国相符;本站支持的每个国家的长度都列在各国 IBAN 格式一文中。

如果只想手动检查一个 IBAN,可以把它粘贴到 IBAN 验证器中:它会显示哪项校验未通过;如果只是校验位不对,还会给出能让它通过的校验位。如果不想自己维护这段代码,可以使用 iban-check,这是我们为 JavaScript 和 TypeScript 开发的开源库。它依据 SWIFT IBAN 注册表完成全部检查,没有任何依赖。可通过 npm 安装:npm install iban-check。

校验能发现哪些错误

这种方法很擅长发现人们打字时犯的错误。任何一位数字输错,或任何两个相邻数字颠倒,都会改变余数,因此一定会被发现。其他错误大约每一百次会漏掉一次。

校验无法判断账户是否存在。校验位正确的 IBAN,仍然可能指向一个不存在的银行代码,或一个已经注销的账户。所以本站生成器生成的 IBAN 虽然没有任何银行发放过,却能通过校验。

国内校验位

有些国家按本国规则计算自己的校验位,放在 BBAN 中。意大利 IBAN 的 BBAN 以一个名为 CIN 的字母开头,法国和摩纳哥的 BBAN 以两位“clé RIB”结尾,西班牙在分行代码和账号之间有两位控制码,比利时的 BBAN 以两位校验位结尾。这些校验与 IBAN 校验位相互独立:一个 IBAN 可能通过了 MOD-97 校验,却没通过国内校验。IBAN 中的国内校验位一文逐国讲解了每种方法。

资料来源

需要测试 IBAN?

为 91 个国家中的任意一个生成有效 IBAN,按需要的格式复制,并查看每一部分的含义。

打开生成器