I wrote a simple Python IBAN validator, which I'd like some reviews on.
INTRO
Quoting from wikipedia, we know that:
The International Bank Account Number (IBAN) is an internationally agreed system of identifying bank accounts across national borders to facilitate the communication and processing of cross border transactions with a reduced risk of transcription errors.
Now, an IBAN may look like this: GB82WEST12345698765432
There are three algorithms to validate an IBAN:
- Validating the IBAN
- Generating IBAN check digits
- Modulo operation on IBAN
I used only the first 2 methods in my program.
1. Validating the IBAN
Description (from wiki):
An IBAN is validated by converting it into an integer and performing a basic mod-97 operation (as described in ISO 7064) on it. If the IBAN is valid, the remainder equals 1. The algorithm of IBAN validation is as follows:
Check that the total IBAN length is correct as per the country. If not, the IBAN is invalid Move the four initial characters to the end of the string Replace each letter in the string with two digits, thereby expanding the string, where A = 10, B = 11, ..., Z = 35 Interpret the string as a decimal integer and compute the remainder of that number on division by 97 If the remainder is 1, the check digit test is passed and the IBAN might be valid.
Example (fictitious United Kingdom bank, sort code 12-34-56, account number 98765432):
• IBAN: GB82WEST12345698765432 • Rearrange: WEST12345698765432GB82 • Convert to integer: 3214282912345698765432161182 • Compute remainder: 3214282912345698765432161182 mod 97 = 1
2. Generating IBAN check digits
Description (from wiki):
According to the ECBS "generation of the IBAN shall be the exclusive responsibility of the bank/branch servicing the account".[8] The ECBS document replicates part of the ISO/IEC 7064:2003 standard as a method for generating check digits in the range 02 to 98. Check digits in the ranges 00 to 96, 01 to 97, and 03 to 99 will also provide validation of an IBAN, but the standard is silent as to whether or not these ranges may be used.
The preferred algorithm is:
- Check that the total IBAN length is correct as per the country.If not, the IBAN is invalid. (I skipped this)
- Replace the two check digits by 00 (e.g. GB00 for the UK)
- Move the four initial characters to the end of the string
- Replace the letters in the string with digits, expanding the string as necessary, such that A or a = 10, B or b = 11, and Z or z = 35. Each alphabetic character is therefore replaced by 2 digits
- Convert the string to an integer (i.e. ignore leading zeroes)
- Calculate mod-97 of the new number, which results in the remainder > 7. Subtract the remainder from 98, and use the result for the two check digits. If the result is a single digit number, pad it with a leading 0 to make a two-digit number
Code (Python 3)
letter_dic = {"A": 10, "B": 11, "C": 12, "D": 13, "E": 14, "F": 15, "G": 16, "H": 17, "I": 18, "J": 19, "K": 20,
"L": 21, "M": 22, "N": 23, "O": 24, "P": 25, "Q": 26, "R": 27, "S": 28, "T": 29, "U": 30, "V": 31,
"W": 32, "X": 33, "Y": 34, "Z": 35,
"0": 0, "1": 1, "2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8, "9": 9}
letters = {ord(k): str(v) for k, v in letter_dic.items()}
def chech_validation_chars_iban(iban):
zeros_iban = iban[:2] + '00' + iban[4:]
iban_inverted = zeros_iban[4:] + zeros_iban[:4]
iban_numbered = iban_inverted.translate(letters)
verification_chars = 98 - (int(iban_numbered) % 97)
if verification_chars < 10:
verification_chars = '{:02}'.format(int(verification_chars))
return verification_chars
def validate_iban(iban):
iban_inverted = iban[4:] + iban[:4]
iban_numbered = iban_inverted.translate(letters)
return int(iban_numbered) % 97
if __name__ == '__main__':
my_iban = 'RO13RZBR0000060007134800'
if chech_validation_chars_iban(my_iban) == int(my_iban[2:4]):
if validate_iban(my_iban) == 1:
print('IBAN ok!\n')
else:
print('IBAN nok!\n')
else:
print('IBAN nok!\n')
Any advice on what could go wrong, tips or improvements are welcome!