PageRenderTime 28ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/core/promogest/lib/iban.py

http://promogest.googlecode.com/
Python | 619 lines | 595 code | 1 blank | 23 comment | 4 complexity | 9e4cf41cc8f12c97451d21722a49761f MD5 | raw file
Possible License(s): GPL-2.0
  1. # -*- coding: utf-8 -*-
  2. #! /usr/bin/env python
  3. """iban.py 0.3 - Create or check International Bank Account Numbers (IBAN).
  4. Copyright (C) 2002-2003, Thomas Günther (toms-cafe.de)
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  16. Usage as module:
  17. from iban import *
  18. code, bank, account = "DE", "12345678", "123456789"
  19. try:
  20. iban = create_iban(code, bank, account)
  21. except IBANError, err:
  22. print err
  23. else:
  24. print " Correct IBAN: %s << %s ?? %s %s" % (iban, code, bank, account)
  25. iban = "de58123456780123456789".upper()
  26. try:
  27. code, checksum, bank, account = check_iban(iban)
  28. except IBANError, err:
  29. print err
  30. else:
  31. print " Correct IBAN: %s >> %s %s %s %s" % (iban, code, checksum,
  32. bank, account)
  33. """
  34. __all__ = ["create_iban", "check_iban", "IBANError"]
  35. usage = \
  36. """Create or check International Bank Account Numbers (IBAN).
  37. Usage: iban <iban>
  38. iban <country> <bank/branch> <account>
  39. iban -h | -f | -e | -t
  40. e.g.: iban DE58123456780123456789
  41. iban DE 12345678 123456789
  42. <iban> is the International Bank Account Number (IBAN)
  43. <country> is the Country Code from ISO 3166
  44. <bank/branch> is the Bank/Branch Code part of the IBAN from ISO 13616
  45. <account> is the Account Number including check digits
  46. iban -h prints this message
  47. iban -f prints a table with the country specific iban format
  48. iban -e prints an example for each country
  49. iban -t prints some test data
  50. Information about IBAN are from European Committee for Banking Standards
  51. (www.ecbs.org/iban.htm). IBAN is an ISO standard (ISO 13616: 1997).
  52. """
  53. class Country:
  54. """Class for country specific iban data."""
  55. def __init__(self, name, code, bank_form, acc_form):
  56. """Constructor for Country objects.
  57. Arguments:
  58. name - Name of the country
  59. code - Country Code from ISO 3166
  60. bank_form - Format of bank/branch code part (e.g. "0 4a 0 ")
  61. acc_form - Format of account number part (e.g. "0 11 2n")
  62. """
  63. self.code = code
  64. self.name = name
  65. self.bank = self._decode_format(bank_form)
  66. self.acc = self._decode_format(acc_form)
  67. def bank_lng(self):
  68. return reduce(lambda sum, part: sum + part[0], self.bank, 0)
  69. def acc_lng(self):
  70. return reduce(lambda sum, part: sum + part[0], self.acc, 0)
  71. def total_lng(self):
  72. return 4 + self.bank_lng() + self.acc_lng()
  73. def _decode_format(self, form):
  74. form_list = []
  75. for part in form.split(" "):
  76. if part:
  77. a_n = part[-1]
  78. if a_n in ("a", "n"):
  79. part = part[:-1]
  80. else:
  81. a_n = "an"
  82. lng = int(part)
  83. form_list.append((lng, a_n))
  84. return tuple(form_list)
  85. # BBAN data from ISO 13616, Country codes from ISO 3166 (www.iso.org).
  86. iban_data = (Country("Andorra", "AD", "0 4n 4n", "0 12 0 "),
  87. Country("Austria", "AT", "0 5n 0 ", "0 11n 0 "),
  88. Country("Belgium", "BE", "0 3n 0 ", "0 7n 2n"),
  89. Country("Switzerland", "CH", "0 5n 0 ", "0 12 0 "),
  90. Country("Czech Republic", "CZ", "0 4n 0 ", "0 16n 0 "),
  91. Country("Germany", "DE", "0 8n 0 ", "0 10n 0 "),
  92. Country("Denmark", "DK", "0 4n 0 ", "0 9n 1n"),
  93. Country("Spain", "ES", "0 4n 4n", "2n 10n 0 "),
  94. Country("Finland", "FI", "0 6n 0 ", "0 7n 1n"),
  95. Country("Faroe Islands", "FO", "0 4n 0 ", "0 9n 1n"),
  96. Country("France", "FR", "0 5n 5n", "0 11 2n"),
  97. Country("United Kingdom", "GB", "0 4a 6n", "0 8n 0 "),
  98. Country("Gibraltar", "GI", "0 4a 0 ", "0 15 0 "),
  99. Country("Greenland", "GL", "0 4n 0 ", "0 9n 1n"),
  100. Country("Greece", "GR", "0 3n 4n", "0 16 0 "),
  101. Country("Hungary", "HU", "0 3n 4n", "1 15 1 "),
  102. Country("Ireland", "IE", "0 4a 6n", "0 8n 0 "),
  103. Country("Iceland", "IS", "0 4n 0 ", "0 18n 0 "),
  104. Country("Italy", "IT", "1a 5n 5n", "0 12 0 "),
  105. Country("Liechtenstein", "LI", "0 5n 0 ", "0 12 0 "),
  106. Country("Luxembourg", "LU", "0 3n 0 ", "0 13 0 "),
  107. Country("Latvia", "LV", "0 4a 0 ", "0 13 0 "),
  108. Country("Monaco", "MC", "0 5n 5n", "0 11 2n"),
  109. Country("Netherlands", "NL", "0 4a 0 ", "0 10n 0 "),
  110. Country("Norway", "NO", "0 4n 0 ", "0 6n 1n"),
  111. Country("Poland", "PL", "0 8n 0 ", "0 16 0 "),
  112. Country("Portugal", "PT", "0 4n 4n", "0 11n 2n"),
  113. Country("Sweden", "SE", "0 3n 0 ", "0 16n 1n"),
  114. Country("Slovenia", "SI", "0 5n 0 ", "0 8n 2n"),
  115. Country("San Marino", "SM", "1a 5n 5n", "0 12 0 "))
  116. def country_data(code):
  117. """Search the country code in the iban_data list."""
  118. for country in iban_data:
  119. if country.code == code:
  120. return country
  121. return None
  122. def mod97(digit_string):
  123. """Modulo 97 for huge numbers given as digit strings.
  124. This function is a prototype for a JavaScript implementation.
  125. In Python this can be done much easier: long(digit_string) % 97.
  126. """
  127. m = 0
  128. for d in digit_string:
  129. m = (m * 10 + int(d)) % 97
  130. return m
  131. def fill0(s, l):
  132. """Fill the string with leading zeros until length is reached."""
  133. import string
  134. return string.zfill(s, l)
  135. def checksum_iban(iban):
  136. """Calculate 2-digit checksum of an IBAN."""
  137. code = iban[:2]
  138. checksum = iban[2:4]
  139. bban = iban[4:]
  140. # Assemble digit string
  141. digits = ""
  142. for ch in bban:
  143. if ch.isdigit():
  144. digits += ch
  145. else:
  146. digits += str(ord(ch) - ord("A") + 10)
  147. for ch in code:
  148. digits += str(ord(ch) - ord("A") + 10)
  149. digits += checksum
  150. # Calculate checksum
  151. checksum = 98 - mod97(digits)
  152. return fill0(str(checksum), 2)
  153. def fill_account(country, account):
  154. """Fill the account number part of IBAN with leading zeros."""
  155. return fill0(account, country.acc_lng())
  156. def invalid_part(form_list, iban_part):
  157. """Check if syntax of the part of IBAN is invalid."""
  158. for lng, a_n in form_list:
  159. if lng > len(iban_part):
  160. lng = len(iban_part)
  161. for ch in iban_part[:lng]:
  162. a = ("A" <= ch <= "Z")
  163. n = ch.isdigit()
  164. if (not a and not n) or \
  165. (not a and a_n == "a") or \
  166. (not n and a_n == "n"):
  167. return 1
  168. iban_part = iban_part[lng:]
  169. return 0
  170. def invalid_bank(country, bank):
  171. """Check if syntax of the bank/branch code part of IBAN is invalid."""
  172. return len(bank) != country.bank_lng() or \
  173. invalid_part(country.bank, bank)
  174. def invalid_account(country, account):
  175. """Check if syntax of the account number part of IBAN is invalid."""
  176. return len(account) > country.acc_lng() or \
  177. invalid_part(country.acc, fill_account(country, account))
  178. def calc_iban(country, bank, account):
  179. """Calculate the checksum and assemble the IBAN."""
  180. account = fill_account(country, account)
  181. checksum = checksum_iban(country.code + "00" + bank + account)
  182. return country.code + checksum + bank + account
  183. def iban_okay(iban):
  184. """Check the checksum of an IBAN."""
  185. return checksum_iban(iban) == "97"
  186. class IBANError(Exception):
  187. def __init__(self, errmsg):
  188. Exception.__init__(self, errmsg)
  189. def create_iban(code, bank, account):
  190. """Check the input, calculate the checksum and assemble the IBAN.
  191. Return the calculated IBAN.
  192. Raise an IBANError exception if the input is not correct.
  193. """
  194. err = None
  195. country = country_data(code)
  196. if not country:
  197. err = "Unknown Country Code: %s" % code
  198. elif len(bank) != country.bank_lng():
  199. err = "Bank/Branch Code length %s is not correct for %s (%s)" % \
  200. (len(bank), country.name, country.bank_lng())
  201. elif invalid_bank(country, bank):
  202. err = "Bank/Branch Code %s is not correct for %s" % \
  203. (bank, country.name)
  204. elif len(account) > country.acc_lng():
  205. err = "Account Number length %s is not correct for %s (%s)" % \
  206. (len(account), country.name, country.acc_lng())
  207. elif invalid_account(country, account):
  208. err = "Account Number %s is not correct for %s" % \
  209. (account, country.name)
  210. if err:
  211. raise IBANError(err)
  212. return calc_iban(country, bank, account)
  213. def check_iban(iban):
  214. """Check the syntax and the checksum of an IBAN.
  215. Return the parts of the IBAN: Country Code, Checksum, Bank/Branch Code and
  216. Account number.
  217. Raise an IBANError exception if the input is not correct.
  218. """
  219. err = None
  220. code = iban[:2]
  221. checksum = iban[2:4]
  222. bban = iban[4:]
  223. country = country_data(code)
  224. if not country:
  225. err = "Codice nazione sconosciuto: %s" % code
  226. elif len(iban) != country.total_lng():
  227. err = "Lunghezza IBAN %s non corretta per %s (%s)" % \
  228. (len(iban), country.name, country.total_lng())
  229. else:
  230. bank_lng = country.bank_lng()
  231. bank = bban[:bank_lng]
  232. account = bban[bank_lng:]
  233. if invalid_bank(country, bank):
  234. err = "Bank/Branch Code %s non ? corretto per %s" % \
  235. (bank, country.name)
  236. elif invalid_account(country, account):
  237. err = "Numero conto %s non ? corretto per %s" % \
  238. (account, country.name)
  239. elif not iban_okay(iban):
  240. err = "IBAN: Non corretto %s >> %s %s %s %s" % \
  241. (iban, code, checksum, bank, account)
  242. if err:
  243. raise IBANError(err)
  244. return code, checksum, bank, account
  245. def print_new_iban(code, bank, account):
  246. """Check the input, calculate the checksum, assemble and print the IBAN."""
  247. try:
  248. iban = create_iban(code, bank, account)
  249. except IBANError, err:
  250. print err
  251. return ""
  252. print " Correct IBAN: %s << %s ?? %s %s" % (iban, code, bank, account)
  253. return iban
  254. def print_iban_parts(iban):
  255. """Check the syntax and the checksum of an IBAN and print the parts."""
  256. try:
  257. code, checksum, bank, account = check_iban(iban)
  258. except IBANError, err:
  259. print err
  260. return ()
  261. print " Correct IBAN: %s >> %s %s %s %s" % (iban, code, checksum,
  262. bank, account)
  263. return code, checksum, bank, account
  264. def print_format():
  265. """Print a table with the country specific iban format."""
  266. print "IBAN-Format (a = alphabetic, n = numeric, an = alphanumeric):"
  267. print " | Bank/Branch-Code | Account Number"
  268. print " Country Code | check1 bank branch |" + \
  269. " check2 number check3"
  270. print "--------------------|-----------------------|" + \
  271. "---------------------"
  272. for country in iban_data:
  273. print country.name.ljust(14), "|", country.code, "|",
  274. for lng, a_n in country.bank:
  275. if lng:
  276. print str(lng).rjust(3), a_n.ljust(2),
  277. else:
  278. print " - ",
  279. print " |",
  280. for lng, a_n in country.acc:
  281. if lng:
  282. print str(lng).rjust(3), a_n.ljust(2),
  283. else:
  284. print " - ",
  285. print
  286. def print_test_data(*data):
  287. """Print a table with iban test data."""
  288. for code, bank, account, checksum in data:
  289. created_iban = print_new_iban(code, bank, account)
  290. if created_iban:
  291. iban = code + checksum + bank + \
  292. fill_account(country_data(code), account)
  293. print_iban_parts(iban)
  294. if iban != created_iban:
  295. print " Changed IBAN"
  296. def print_examples():
  297. print "IBAN-Examples:"
  298. print_test_data(("AD", "00012030", "200359100100", "12"),
  299. ("AT", "19043", "00234573201", "61"),
  300. ("BE", "539", "007547034", "68"),
  301. ("CH", "00762", "011623852957", "93"),
  302. ("CZ", "0800", "0000192000145399", "65"),
  303. ("DE", "37040044", "0532013000", "89"),
  304. ("DK", "0040", "0440116243", "50"),
  305. ("ES", "21000418", "450200051332", "91"),
  306. ("FI", "123456", "00000785", "21"),
  307. ("FO", "0040", "0440116243", "20"),
  308. ("FR", "2004101005", "0500013M02606", "14"),
  309. ("GB", "NWBK601613", "31926819", "29"),
  310. ("GI", "NWBK", "000000007099453", "75"),
  311. ("GL", "0040", "0440116243", "20"),
  312. ("GR", "0110125", "0000000012300695", "16"),
  313. ("HU", "1177301", "61111101800000000", "42"),
  314. ("IE", "AIBK931152", "12345678", "29"),
  315. ("IS", "0159", "260076545510730339", "14"),
  316. ("IT", "X0542811101", "000000123456", "60"),
  317. ("LI", "00762", "011623852957", "09"),
  318. ("LU", "001", "9400644750000", "28"),
  319. ("LV", "BANK", "0000435195001", "80"),
  320. ("MC", "2004101005", "0500013M02606", "93"),
  321. ("NL", "ABNA", "0417164300", "91"),
  322. ("NO", "8601", "1117947", "93"),
  323. ("PL", "11402004", "0000300201355387", "27"),
  324. ("PT", "00020123", "1234567890154", "50"),
  325. ("SE", "500", "00000054910000003", "35"),
  326. ("SI", "19100", "0000123438", "56"),
  327. ("SM", "X0542811101", "000000123456", "88"))
  328. def print_test():
  329. print "IBAN-Test:"
  330. print_test_data(("XY", "1", "2", "33"),
  331. ("AD", "11112222", "C3C3C3C3C3C3", "11"),
  332. ("AD", "1111222", "C3C3C3C3C3C3", "11"),
  333. ("AD", "X1112222", "C3C3C3C3C3C3", "11"),
  334. ("AD", "111@2222", "C3C3C3C3C3C3", "11"),
  335. ("AD", "1111X222", "C3C3C3C3C3C3", "11"),
  336. ("AD", "1111222@", "C3C3C3C3C3C3", "11"),
  337. ("AD", "11112222", "@3C3C3C3C3C3", "11"),
  338. ("AD", "11112222", "C3C3C3C3C3C@", "11"),
  339. ("AT", "11111", "22222222222", "17"),
  340. ("AT", "1111", "22222222222", "17"),
  341. ("AT", "X1111", "22222222222", "17"),
  342. ("AT", "1111@", "22222222222", "17"),
  343. ("AT", "11111", "X2222222222", "17"),
  344. ("AT", "11111", "2222222222@", "17"),
  345. ("BE", "111", "222222233", "93"),
  346. ("BE", "11", "222222233", "93"),
  347. ("BE", "X11", "222222233", "93"),
  348. ("BE", "11@", "222222233", "93"),
  349. ("BE", "111", "X22222233", "93"),
  350. ("BE", "111", "222222@33", "93"),
  351. ("BE", "111", "2222222X3", "93"),
  352. ("BE", "111", "22222223@", "93"),
  353. ("CH", "11111", "B2B2B2B2B2B2", "60"),
  354. ("CH", "1111", "B2B2B2B2B2B2", "60"),
  355. ("CH", "X1111", "B2B2B2B2B2B2", "60"),
  356. ("CH", "1111@", "B2B2B2B2B2B2", "60"),
  357. ("CH", "11111", "@2B2B2B2B2B2", "60"),
  358. ("CH", "11111", "B2B2B2B2B2B@", "60"),
  359. ("CZ", "1111", "2222222222222222", "68"),
  360. ("CZ", "111", "2222222222222222", "68"),
  361. ("CZ", "X111", "2222222222222222", "68"),
  362. ("CZ", "111@", "2222222222222222", "68"),
  363. ("CZ", "1111", "X222222222222222", "68"),
  364. ("CZ", "1111", "222222222222222@", "68"),
  365. ("DE", "11111111", "2222222222", "16"),
  366. ("DE", "1111111", "2222222222", "16"),
  367. ("DE", "X1111111", "2222222222", "16"),
  368. ("DE", "1111111@", "2222222222", "16"),
  369. ("DE", "11111111", "X222222222", "16"),
  370. ("DE", "11111111", "222222222@", "16"),
  371. ("DK", "1111", "2222222223", "79"),
  372. ("DK", "111", "2222222223", "79"),
  373. ("DK", "X111", "2222222223", "79"),
  374. ("DK", "111@", "2222222223", "79"),
  375. ("DK", "1111", "X222222223", "79"),
  376. ("DK", "1111", "22222222@3", "79"),
  377. ("DK", "1111", "222222222X", "79"),
  378. ("ES", "11112222", "334444444444", "71"),
  379. ("ES", "1111222", "334444444444", "71"),
  380. ("ES", "X1112222", "334444444444", "71"),
  381. ("ES", "111@2222", "334444444444", "71"),
  382. ("ES", "1111X222", "334444444444", "71"),
  383. ("ES", "1111222@", "334444444444", "71"),
  384. ("ES", "11112222", "X34444444444", "71"),
  385. ("ES", "11112222", "3@4444444444", "71"),
  386. ("ES", "11112222", "33X444444444", "71"),
  387. ("ES", "11112222", "33444444444@", "71"),
  388. ("FI", "111111", "22222223", "68"),
  389. ("FI", "11111", "22222223", "68"),
  390. ("FI", "X11111", "22222223", "68"),
  391. ("FI", "11111@", "22222223", "68"),
  392. ("FI", "111111", "X2222223", "68"),
  393. ("FI", "111111", "222222@3", "68"),
  394. ("FI", "111111", "2222222X", "68"),
  395. ("FO", "1111", "2222222223", "49"),
  396. ("FO", "111", "2222222223", "49"),
  397. ("FO", "X111", "2222222223", "49"),
  398. ("FO", "111@", "2222222223", "49"),
  399. ("FO", "1111", "X222222223", "49"),
  400. ("FO", "1111", "22222222@3", "49"),
  401. ("FO", "1111", "222222222X", "49"),
  402. ("FR", "1111122222", "C3C3C3C3C3C44", "44"),
  403. ("FR", "111112222", "C3C3C3C3C3C44", "44"),
  404. ("FR", "X111122222", "C3C3C3C3C3C44", "44"),
  405. ("FR", "1111@22222", "C3C3C3C3C3C44", "44"),
  406. ("FR", "11111X2222", "C3C3C3C3C3C44", "44"),
  407. ("FR", "111112222@", "C3C3C3C3C3C44", "44"),
  408. ("FR", "1111122222", "@3C3C3C3C3C44", "44"),
  409. ("FR", "1111122222", "C3C3C3C3C3@44", "44"),
  410. ("FR", "1111122222", "C3C3C3C3C3CX4", "44"),
  411. ("FR", "1111122222", "C3C3C3C3C3C4@", "44"),
  412. ("GB", "AAAA222222", "33333333", "45"),
  413. ("GB", "AAAA22222", "33333333", "45"),
  414. ("GB", "8AAA222222", "33333333", "45"),
  415. ("GB", "AAA@222222", "33333333", "45"),
  416. ("GB", "AAAAX22222", "33333333", "45"),
  417. ("GB", "AAAA22222@", "33333333", "45"),
  418. ("GB", "AAAA222222", "X3333333", "45"),
  419. ("GB", "AAAA222222", "3333333@", "45"),
  420. ("GI", "AAAA", "B2B2B2B2B2B2B2B", "72"),
  421. ("GI", "AAA", "B2B2B2B2B2B2B2B", "72"),
  422. ("GI", "8AAA", "B2B2B2B2B2B2B2B", "72"),
  423. ("GI", "AAA@", "B2B2B2B2B2B2B2B", "72"),
  424. ("GI", "AAAA", "@2B2B2B2B2B2B2B", "72"),
  425. ("GI", "AAAA", "B2B2B2B2B2B2B2@", "72"),
  426. ("GL", "1111", "2222222223", "49"),
  427. ("GL", "111", "2222222223", "49"),
  428. ("GL", "X111", "2222222223", "49"),
  429. ("GL", "111@", "2222222223", "49"),
  430. ("GL", "1111", "X222222223", "49"),
  431. ("GL", "1111", "22222222@3", "49"),
  432. ("GL", "1111", "222222222X", "49"),
  433. ("GR", "1112222", "C3C3C3C3C3C3C3C3", "61"),
  434. ("GR", "111222", "C3C3C3C3C3C3C3C3", "61"),
  435. ("GR", "X112222", "C3C3C3C3C3C3C3C3", "61"),
  436. ("GR", "11@2222", "C3C3C3C3C3C3C3C3", "61"),
  437. ("GR", "111X222", "C3C3C3C3C3C3C3C3", "61"),
  438. ("GR", "111222@", "C3C3C3C3C3C3C3C3", "61"),
  439. ("GR", "1112222", "@3C3C3C3C3C3C3C3", "61"),
  440. ("GR", "1112222", "C3C3C3C3C3C3C3C@", "61"),
  441. ("HU", "1112222", "CD4D4D4D4D4D4D4D5", "36"),
  442. ("HU", "111222", "CD4D4D4D4D4D4D4D5", "36"),
  443. ("HU", "X112222", "CD4D4D4D4D4D4D4D5", "36"),
  444. ("HU", "11@2222", "CD4D4D4D4D4D4D4D5", "36"),
  445. ("HU", "111X222", "CD4D4D4D4D4D4D4D5", "36"),
  446. ("HU", "111222@", "CD4D4D4D4D4D4D4D5", "36"),
  447. ("HU", "1112222", "@D4D4D4D4D4D4D4D5", "36"),
  448. ("HU", "1112222", "C@4D4D4D4D4D4D4D5", "36"),
  449. ("HU", "1112222", "CD4D4D4D4D4D4D4@5", "36"),
  450. ("HU", "1112222", "CD4D4D4D4D4D4D4D@", "36"),
  451. ("IE", "AAAA222222", "33333333", "18"),
  452. ("IE", "AAAA22222", "33333333", "18"),
  453. ("IE", "8AAA222222", "33333333", "18"),
  454. ("IE", "AAA@222222", "33333333", "18"),
  455. ("IE", "AAAAX22222", "33333333", "18"),
  456. ("IE", "AAAA22222@", "33333333", "18"),
  457. ("IE", "AAAA222222", "X3333333", "18"),
  458. ("IE", "AAAA222222", "3333333@", "18"),
  459. ("IS", "1111", "222222222222222222", "98"),
  460. ("IS", "111", "222222222222222222", "98"),
  461. ("IS", "X111", "222222222222222222", "98"),
  462. ("IS", "111@", "222222222222222222", "98"),
  463. ("IS", "1111", "X22222222222222222", "98"),
  464. ("IS", "1111", "22222222222222222@", "98"),
  465. ("IT", "A2222233333", "D4D4D4D4D4D4", "43"),
  466. ("IT", "A222223333", "D4D4D4D4D4D4", "43"),
  467. ("IT", "82222233333", "D4D4D4D4D4D4", "43"),
  468. ("IT", "AX222233333", "D4D4D4D4D4D4", "43"),
  469. ("IT", "A2222@33333", "D4D4D4D4D4D4", "43"),
  470. ("IT", "A22222X3333", "D4D4D4D4D4D4", "43"),
  471. ("IT", "A222223333@", "D4D4D4D4D4D4", "43"),
  472. ("IT", "A2222233333", "@4D4D4D4D4D4", "43"),
  473. ("IT", "A2222233333", "D4D4D4D4D4D@", "43"),
  474. ("LI", "11111", "B2B2B2B2B2B2", "73"),
  475. ("LI", "1111", "B2B2B2B2B2B2", "73"),
  476. ("LI", "X1111", "B2B2B2B2B2B2", "73"),
  477. ("LI", "1111@", "B2B2B2B2B2B2", "73"),
  478. ("LI", "11111", "@2B2B2B2B2B2", "73"),
  479. ("LI", "11111", "B2B2B2B2B2B@", "73"),
  480. ("LU", "111", "B2B2B2B2B2B2B", "27"),
  481. ("LU", "11", "B2B2B2B2B2B2B", "27"),
  482. ("LU", "X11", "B2B2B2B2B2B2B", "27"),
  483. ("LU", "11@", "B2B2B2B2B2B2B", "27"),
  484. ("LU", "111", "@2B2B2B2B2B2B", "27"),
  485. ("LU", "111", "B2B2B2B2B2B2@", "27"),
  486. ("LV", "AAAA", "B2B2B2B2B2B2B", "86"),
  487. ("LV", "AAA", "B2B2B2B2B2B2B", "86"),
  488. ("LV", "8AAA", "B2B2B2B2B2B2B", "86"),
  489. ("LV", "AAA@", "B2B2B2B2B2B2B", "86"),
  490. ("LV", "AAAA", "@2B2B2B2B2B2B", "86"),
  491. ("LV", "AAAA", "B2B2B2B2B2B2@", "86"),
  492. ("MC", "1111122222", "C3C3C3C3C3C44", "26"),
  493. ("MC", "111112222", "C3C3C3C3C3C44", "26"),
  494. ("MC", "X111122222", "C3C3C3C3C3C44", "26"),
  495. ("MC", "1111@22222", "C3C3C3C3C3C44", "26"),
  496. ("MC", "11111X2222", "C3C3C3C3C3C44", "26"),
  497. ("MC", "111112222@", "C3C3C3C3C3C44", "26"),
  498. ("MC", "1111122222", "@3C3C3C3C3C44", "26"),
  499. ("MC", "1111122222", "C3C3C3C3C3@44", "26"),
  500. ("MC", "1111122222", "C3C3C3C3C3CX4", "26"),
  501. ("MC", "1111122222", "C3C3C3C3C3C4@", "26"),
  502. ("NL", "AAAA", "2222222222", "57"),
  503. ("NL", "AAA", "2222222222", "57"),
  504. ("NL", "8AAA", "2222222222", "57"),
  505. ("NL", "AAA@", "2222222222", "57"),
  506. ("NL", "AAAA", "X222222222", "57"),
  507. ("NL", "AAAA", "222222222@", "57"),
  508. ("NO", "1111", "2222223", "40"),
  509. ("NO", "111", "2222223", "40"),
  510. ("NO", "X111", "2222223", "40"),
  511. ("NO", "111@", "2222223", "40"),
  512. ("NO", "1111", "X222223", "40"),
  513. ("NO", "1111", "22222@3", "40"),
  514. ("NO", "1111", "222222X", "40"),
  515. ("PL", "11111111", "B2B2B2B2B2B2B2B2", "16"),
  516. ("PL", "1111111", "B2B2B2B2B2B2B2B2", "16"),
  517. ("PL", "X1111111", "B2B2B2B2B2B2B2B2", "16"),
  518. ("PL", "1111111@", "B2B2B2B2B2B2B2B2", "16"),
  519. ("PL", "11111111", "@2B2B2B2B2B2B2B2", "16"),
  520. ("PL", "11111111", "B2B2B2B2B2B2B2B@", "16"),
  521. ("PT", "11112222", "3333333333344", "59"),
  522. ("PT", "1111222", "3333333333344", "59"),
  523. ("PT", "X1112222", "3333333333344", "59"),
  524. ("PT", "111@2222", "3333333333344", "59"),
  525. ("PT", "1111X222", "3333333333344", "59"),
  526. ("PT", "1111222@", "3333333333344", "59"),
  527. ("PT", "11112222", "X333333333344", "59"),
  528. ("PT", "11112222", "3333333333@44", "59"),
  529. ("PT", "11112222", "33333333333X4", "59"),
  530. ("PT", "11112222", "333333333334@", "59"),
  531. ("SE", "111", "22222222222222223", "32"),
  532. ("SE", "11", "22222222222222223", "32"),
  533. ("SE", "X11", "22222222222222223", "32"),
  534. ("SE", "11@", "22222222222222223", "32"),
  535. ("SE", "111", "X2222222222222223", "32"),
  536. ("SE", "111", "222222222222222@3", "32"),
  537. ("SE", "111", "2222222222222222X", "32"),
  538. ("SI", "11111", "2222222233", "92"),
  539. ("SI", "1111", "2222222233", "92"),
  540. ("SI", "X1111", "2222222233", "92"),
  541. ("SI", "1111@", "2222222233", "92"),
  542. ("SI", "11111", "X222222233", "92"),
  543. ("SI", "11111", "2222222@33", "92"),
  544. ("SI", "11111", "22222222X3", "92"),
  545. ("SI", "11111", "222222223@", "92"),
  546. ("SM", "A2222233333", "D4D4D4D4D4D4", "71"),
  547. ("SM", "A222223333", "D4D4D4D4D4D4", "71"),
  548. ("SM", "82222233333", "D4D4D4D4D4D4", "71"),
  549. ("SM", "AX222233333", "D4D4D4D4D4D4", "71"),
  550. ("SM", "A2222@33333", "D4D4D4D4D4D4", "71"),
  551. ("SM", "A22222X3333", "D4D4D4D4D4D4", "71"),
  552. ("SM", "A222223333@", "D4D4D4D4D4D4", "71"),
  553. ("SM", "A2222233333", "@4D4D4D4D4D4", "71"),
  554. ("SM", "A2222233333", "D4D4D4D4D4D@", "71"),
  555. ("DE", "12345678", "5", "06"))
  556. # Main program (executed unless imported as module)
  557. if __name__ == "__main__":
  558. import sys
  559. if len(sys.argv) == 4:
  560. print_new_iban(sys.argv[1].upper(), sys.argv[2].upper(),
  561. sys.argv[3].upper())
  562. elif len(sys.argv) == 2 and sys.argv[1][0] != "-":
  563. print_iban_parts(sys.argv[1].upper())
  564. elif "-f" in sys.argv[1:2]:
  565. print_format()
  566. elif "-e" in sys.argv[1:2]:
  567. print_examples()
  568. elif "-t" in sys.argv[1:2]:
  569. print_test()
  570. else:
  571. print usage