Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
106
Task/IBAN/OCaml/iban.ocaml
Normal file
106
Task/IBAN/OCaml/iban.ocaml
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
#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
|
||||
Loading…
Add table
Add a link
Reference in a new issue