95 lines
3.6 KiB
Python
Executable file
95 lines
3.6 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
|
|
import re
|
|
import csv
|
|
import json
|
|
|
|
#import httpx
|
|
|
|
|
|
#iban_registry_url = "https://www.swift.com/sites/default/files/files/iban-registry_1.txt"
|
|
#iban_registry_raw = httpx.get(iban_registry_url)
|
|
|
|
data = []
|
|
|
|
with open("iban-registry_1.txt", encoding="cp437") as csvfile:
|
|
reader = csv.reader(csvfile, delimiter="\t", quotechar='"')
|
|
for row in reader:
|
|
match row[0]:
|
|
case "Name of country":
|
|
for col in row[1:]:
|
|
data.append({"name": " ".join(reversed(col.split(", ")))})
|
|
case "IBAN prefix country code (ISO 3166)":
|
|
for i, col in enumerate(row[1:]):
|
|
data[i]["prefix"] = col
|
|
case "SEPA country":
|
|
for i, col in enumerate(row[1:]):
|
|
data[i]["sepa"] = True if col == "Yes" else False
|
|
case "IBAN structure":
|
|
for i, col in enumerate(row[1:]):
|
|
data[i]["format"] = col
|
|
case "BBAN structure":
|
|
for i, col in enumerate(row[1:]):
|
|
data[i]["regex"] = f"/^{data[i]['prefix']}[0-9]{{2}}"
|
|
for match in re.findall(r"(\d+)(!?)([ance])", col):
|
|
match match[2]:
|
|
case "a":
|
|
data[i]["regex"] += "[A-Z]"
|
|
case "n":
|
|
data[i]["regex"] += "[0-9]"
|
|
case "c":
|
|
data[i]["regex"] += "[0-9a-zA-Z]"
|
|
case "e":
|
|
data[i]["regex"] += "[ ]"
|
|
print(f"{data[i]['prefix']} has spaces")
|
|
if match[1] == "!":
|
|
data[i]["regex"] += f"{{{match[0]}}}"
|
|
else:
|
|
data[i]["regex"] += f"{{1,{match[0]}}}"
|
|
print(f"{data[i]['prefix']} has no !")
|
|
data[i]["regex"] += "$/"
|
|
case "IBAN length":
|
|
for i, col in enumerate(row[1:]):
|
|
data[i]["length"] = int(col)
|
|
case "Effective date":
|
|
for i, col in enumerate(row[1:]):
|
|
data[i]["since"] = col
|
|
case "Last update date":
|
|
for i, col in enumerate(row[1:]):
|
|
data[i]["updated"] = col
|
|
|
|
#print(json.dumps(data))
|
|
|
|
print("""/*
|
|
* function generated with iban_validator_gen.py
|
|
* with iban registry text file from:
|
|
* https://www.swift.com/standards/data-standards/iban-international-bank-account-number
|
|
*/
|
|
export function testIban(iban) {
|
|
let re = /^$/;
|
|
let error = "IBAN is not ISO 13616 compliant";
|
|
// Also validate lower case country codes but display error int the end
|
|
switch (iban.substring(0,2).toUpperCase()) {""")
|
|
for country in data:
|
|
print(f""" case "{country['prefix']}":
|
|
re = {country['regex']};
|
|
error = "IBAN for {country['name']} must have the format {country['format']}.";
|
|
break;""")
|
|
print(""" }
|
|
if (re.test(iban)) {
|
|
console.log("IBAN regex evaluates");
|
|
/*
|
|
* ISO/IEC 7064 checksum evaluation
|
|
* 1. shift first 4 chars of IBAN to the end
|
|
* 2. replace letter with numbers where a=10, b=11, ..., z=35
|
|
* 3. modulo the resulting number by 97
|
|
* 4. IBAN is valid if the result is 1
|
|
*/
|
|
return BigInt((iban.slice(4) + iban.slice(0, 4)).split("").map(ch => {
|
|
return isNaN(Number(ch)) ? ch.toLowerCase().charCodeAt(0) - 87 : ch
|
|
}).join("")) % 97n === 1n ? "" : `IBAN checksum not correct. ${error}`;
|
|
} else {
|
|
return error
|
|
}
|
|
};
|
|
""")
|