

 This page uses content from Wikipedia. The original article was at IBAN. The list of authors can be seen in the page history. As with Rosetta Code, the text of Wikipedia is available under the GNU FDL. (See links for details on variance)



The   International Bank Account Number (IBAN)   is an internationally agreed means of identifying bank accounts across national borders with a reduced risk of propagating transcription errors.

The IBAN consists of up to 34 alphanumeric characters:

   first the two-letter ISO 3166-1 alpha-2 country code, 
   then two check digits, and 
   finally a country-specific Basic Bank Account Number (BBAN). 


The check digits enable a sanity check of the bank account number to confirm its integrity even before submitting a transaction.



Task

Validate the following fictitious IBAN:    GB82 WEST 1234 5698 7654 32 



Details of the algorithm can be found on the Wikipedia page.




(* country_code : string -> int *)
(* Get the length of a valid IBAN given the two chars long country code *)
fun country_code (str : string) : int =
  case str of
    "AL" => 28 | "AD" => 24 | "AT" => 20 | "AZ" => 28
  | "BE" => 16 | "BH" => 22 | "BA" => 20 | "BR" => 29
  | "BG" => 22 | "CR" => 21 | "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 | "KZ" => 20 | "KW" => 30
  | "LV" => 21 | "LB" => 28 | "LI" => 21 | "LT" => 20
  | "LU" => 20 | "MK" => 19 | "MT" => 31 | "MR" => 27
  | "MU" => 30 | "MC" => 27 | "MD" => 24 | "ME" => 22
  | "NL" => 18 | "NO" => 15 | "PK" => 24 | "PS" => 29
  | "PL" => 28 | "PT" => 25 | "RO" => 24 | "SM" => 27
  | "SA" => 24 | "RS" => 22 | "SK" => 24 | "SI" => 19
  | "ES" => 24 | "SE" => 24 | "CH" => 21 | "TN" => 24
  | "TR" => 26 | "AE" => 23 | "GB" => 22 | "VG" => 24
  | _ => raise Domain
 
 
(* removespace : string -> string *)
(* Removes all spaces from a string *)
fun removespace s = String.translate (fn #" " => "" | c => str c) s
 
(* to_upper : string -> string *)
(* Convert every char to upper of a string *)
fun to_upper (s : string) : string =
  String.translate (fn c => str (Char.toUpper c)) s
 
(* convert_to_number : char -> string *)
(* Covert a alphanumeric char into a numerical string *)
fun convert_to_number (c : char) : string =
  if Char.isDigit c then str c else
    if Char.isUpper c then Int.toString (10 + ord c - ord #"A") else
      raise Domain
 
 
(* verify_iban : string -> bool *)
(* Check weather a string is a valid IBAN *)
fun verify_iban str =
  let
    (* Remove spaces and make upper case *)
    val str = to_upper (removespace str)
    (* Fetch first two chars (country code) *)
    val country = String.substring (str, 0, 2)
    val len = country_code country
  in
    (* size test *)
    String.size str = len
    andalso
    (* Every char must be alphanumeric *)
    List.all Char.isAlphaNum (explode str)
    andalso
    let
      (* Reorder *)
      val str = String.substring (str, 4, String.size str - 4) ^ String.substring (str, 0, 4)
      (* Convert into digits *)
      val str = String.translate convert_to_number str
      (* Convert into a big number *)
      val number = valOf (IntInf.fromString str)
    in
      IntInf.mod (number, 97) = 1
    end
  end handle Subscript => false | Domain => false