IBAN Validation With Mod-97
Normalize and validate international bank account numbers using country lengths and the ISO 7064 mod-97 checksum.
Code
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;
}Report a problem with this exampleOpens a pre-filled issue on GitHub.