IBAN: Difference between revisions

4,633 bytes added ,  7 years ago
OCaml
No edit summary
(OCaml)
Line 2,252:
IBAN[XX0380000000608010167519]=Country XX not has IBAN codes. FALSE
</pre>
 
 
=={{header|OCaml}}==
{{works with|OCaml|4.03+}}
<lang ocaml>
#load "str.cma"
#load "nums.cma" (* for module Big_int *)
 
 
(* Countries and length of their IBAN. *)
(* Taken from https://en.wikipedia.org/wiki/International_Bank_Account_Number#IBAN_formats_by_country *)
let countries = [
("AL", 28); ("AD", 24); ("AT", 20); ("AZ", 28); ("BH", 22); ("BE", 16);
("BA", 20); ("BR", 29); ("BG", 22); ("CR", 21); ("HR", 21); ("CY", 28);
("CZ", 24); ("DK", 18); ("DO", 28); ("TL", 23); ("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); ("JO", 30); ("KZ", 20); ("XK", 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); ("QA", 29);
("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); ("DZ", 24); ("AO", 25); ("BJ", 28); ("BF", 27);
("BI", 16); ("CM", 27); ("CV", 25); ("IR", 26); ("CI", 28); ("MG", 27);
("ML", 28); ("MZ", 25); ("SN", 28); ("UA", 29)
]
(* Put the countries in a Hashtbl for faster search... *)
let tbl_countries =
let htbl = Hashtbl.create (List.length countries) in
let _ = List.iter (fun (k, v) -> Hashtbl.add htbl k v) countries in
htbl
 
 
(* Delete spaces and put all letters in upper case. *)
let clean_iban iban =
Str.global_replace (Str.regexp " +") "" iban
|> String.uppercase_ascii
 
 
(* Each country has an IBAN with a specific length. *)
let check_length ib =
let iso_length = List.hd countries |> fst |> String.length in
let country_code = String.sub ib 0 iso_length in
try
Hashtbl.find tbl_countries country_code = String.length ib
with
Not_found -> false
 
 
(* Convert a string into a list of chars. *)
let charlist_of_string s =
let l = String.length s in
let rec doloop i =
if i >= l then []
else s.[i] :: doloop (i + 1)
in
doloop 0
 
 
(* Letters are associated to values: A=10, B=11, ..., Z=35. *)
let val_of_char c =
match c with
| '0' .. '9' -> int_of_char c - int_of_char '0'
| 'A' .. 'Z' -> int_of_char c - int_of_char 'A' + 10
| _ -> failwith (Printf.sprintf "Character not allowed: %c" c)
 
 
(* Compute the mod-97 value and check it is equal to 1. *)
let check_mod97 ib =
let l = String.length ib
and taken = 4 in
let prefix = String.sub ib 0 taken
and rest = String.sub ib taken (l - taken) in
let newval = rest ^ prefix (* move the 4 initial characters to the end of the string *)
|> charlist_of_string (* convert the string into a list of chars *)
|> List.map val_of_char (* convert each char into its integer value *)
|> List.map string_of_int (* convert the integers into strings... *)
|> List.fold_left (^) "" in (* ...and concatenate said strings *)
(* Now compute the mod-97 using the Big Integers provided by OCaml, and
* compare the result to 1. *)
Big_int.eq_big_int
(Big_int.mod_big_int (Big_int.big_int_of_string newval)
(Big_int.big_int_of_int 97))
(Big_int.big_int_of_int 1)
 
 
(* Do the validation as described in the Wikipedia article at
* https://en.wikipedia.org/wiki/International_Bank_Account_Number#Validating_the_IBAN *)
let validate iban =
let ib = clean_iban iban in
check_length ib && check_mod97 ib
 
 
let () =
let ibans = [
("GB82 WEST 1234 5698 7654 32", true);
("GB82 TEST 1234 5698 7654 32", false);
("GB81 WEST 1234 5698 7654 32", false);
("GB82 WEST 1234 5698 7654 3", false);
("SA03 8000 0000 6080 1016 7519", true);
("CH93 0076 2011 6238 5295 7", true);
("\"Completely incorrect iban\"", false)
] in
let testit (ib, exp) =
let res = validate ib in
Printf.printf "%s is %svalid. Expected %b [%s]\n"
ib (if res then "" else "not ")
exp (if res = exp then "PASS" else "FAIL")
in
List.iter (fun pair -> testit pair) ibans
</lang>
{{out}}
GB82 WEST 1234 5698 7654 32 is valid. Expected true [PASS]
GB82 TEST 1234 5698 7654 32 is not valid. Expected false [PASS]
GB81 WEST 1234 5698 7654 32 is not valid. Expected false [PASS]
GB82 WEST 1234 5698 7654 3 is not valid. Expected false [PASS]
SA03 8000 0000 6080 1016 7519 is valid. Expected true [PASS]
CH93 0076 2011 6238 5295 7 is valid. Expected true [PASS]
"Completely incorrect iban" is not valid. Expected false [PASS]
 
 
=={{header|Perl}}==
Anonymous user