IBAN number check refreshed

TrustyTony 2 Tallied Votes 413 Views Share

Picked up from old thread but currently applicable (the IBAN number became more widely required actually this year in Finland). The style was quite alien for modern Python coders, so I massaged the code to my own liking. I removed many temporary variables, as for my opinion they did not make things cleared, and I reformed map lambdas to generators.

# Utility to check the integrity of an IBAN bank account No.
# based on old code in thread: http://www.daniweb.com/software-development/python/threads/238464
# Dictionaries - Refer to ISO 7064 mod 97-10 
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}

# ISO 3166-1 alpha-2 country code
country_dic={"AL":[28,"Albania"],
             "AD":[24,"Andorra"],
             "AT":[20,"Austria"],
             "BE":[16,"Belgium"],
             "BA":[20,"Bosnia"],
             "BG":[22,"Bulgaria"],
             "HR":[21,"Croatia"],
             "CY":[28,"Cyprus"],
             "CZ":[24,"Czech Republic"],
             "DK":[18,"Denmark"],
             "EE":[20,"Estonia"],
             "FO":[18,"Faroe Islands"],
             "FI":[18,"Finland"],
             "FR":[27,"France"],
             "DE":[22,"Germany"],
             "GI":[23,"Gibraltar"],
             "GR":[27,"Greece"],
             "GL":[18,"Greenland"],
             "HU":[28,"Hungary"],
             "IS":[26,"Iceland"],
             "IE":[22,"Ireland"],
             "IL":[23,"Israel"],
             "IT":[27,"Italy"],
             "LV":[21,"Latvia"],
             "LI":[21,"Liechtenstein"],
             "LT":[20,"Lithuania"],
             "LU":[20,"Luxembourg"],
             "MK":[19,"Macedonia"],
             "MT":[31,"Malta"],
             "MU":[30,"Mauritius"],
             "MC":[27,"Monaco"],
             "ME":[22,"Montenegro"],
             "NL":[18,"Netherlands"],
             "NO":[15,"Northern Ireland"],
             "PO":[28,"Poland"],
             "PT":[25,"Portugal"],
             "RO":[24,"Romania"],
             "SM":[27,"San Marino"],
             "SA":[24,"Saudi Arabia"],
             "RS":[22,"Serbia"],
             "SK":[24,"Slovakia"],
             "SI":[19,"Slovenia"],
             "ES":[24,"Spain"],
             "SE":[24,"Sweden"],
             "CH":[21,"Switzerland"],
             "TR":[26,"Turkey"],
             "TN":[24,"Tunisia"],
             "GB":[22,"United Kingdom"]}

def check(orig):
    block = 4
    # remove spaces from formatted 
    IBAN = ''.join(c for c in orig if c.isalnum())
    
    IBAN = IBAN[4:] + IBAN[:4]
    country = IBAN[-4:-2]
    
    if country not in country_dic:
        raise ValueError('Unknown IBAN country %s' % country)

    length_c, name_c = country_dic[country]

    if len(IBAN) != length_c:
        diff = len(IBAN) - length_c
        raise ValueError('Wrong IBAN length by %s: %s' % (('short by %i' % -diff) if diff < 0 else
                                                          ('too long by %i' % diff), orig))
    elif int("".join(str(letter_dic[x]) for x in IBAN)) % 97 != 1:
        raise ValueError('Incorrect IBAN number: %s' % orig)
    else:
        # Accepted: 
        # move IBAN to original order
        IBAN = IBAN[-4:] + IBAN[:-4]
        # return formatted number with spaces
        return ' '.join(IBAN[f:f+block] for f in range(0, len(IBAN), block))

if __name__ == '__main__':
    # Sample IBAN account numbers.
    for  IBAN in ("GB35MIDL40253432144670", "BE31435411161155", "CH5108686001256515001", raw_input("Enter account No. : ").upper()):
        try:
            formatted = check(IBAN)
        except ValueError as e:
            print(e)
        else:
            print("IBAN account No. accepted.")
            print("Formated bank account No : %s\n" % formatted)
TrustyTony 888 ex-Moderator Team Colleague Featured Poster

Of course there is more consise way of doing the first line, but it does not really matter:

letter_dic= dict((letter, ind) for ind, letter in enumerate("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"))
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.