RosettaCodeData/Task/Password-generator/OCaml/password-generator.ml

58 lines
1.5 KiB
OCaml

let lower = "abcdefghijklmnopqrstuvwxyz"
let upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
let digit = "0123456789"
let other = "!\034#$%&'()*+,-./:;<=>?@[]^_{|}~"
let visually_similar = "Il1O05S2Z"
let mk_pwd len readable =
let get_char i =
match i mod 4 with
| 0 -> lower.[Random.int (String.length lower)]
| 1 -> upper.[Random.int (String.length upper)]
| 2 -> digit.[Random.int (String.length digit)]
| 3 -> other.[Random.int (String.length other)]
| _ -> raise Exit
in
let f =
if readable then
(fun i ->
let rec aux () =
let c = get_char i in
if String.contains visually_similar c
then aux ()
else (String.make 1 c)
in
aux ()
)
else
(fun i ->
let c = get_char i in
(String.make 1 c)
)
in
let r = Array.init len f in
Array.sort (fun _ _ -> (Random.int 3) - 1) r;
(String.concat "" (Array.to_list r))
let () =
Random.self_init ();
let num = ref 1 in
let len = ref 8 in
let readable = ref false in
let speclist = [
"-n", Arg.Set_int num, "number of passwords";
"-c", Arg.Set_int len, "number of characters";
"--readable", Arg.Set readable, "readable";
"--rand-init", Arg.String (fun s ->
Random.full_init
(Array.map int_of_char (Array.of_seq (String.to_seq s)))
), "initialise the random generator with a string";
] in
Arg.parse speclist (fun s -> invalid_arg s) "Password generator";
for i = 1 to !num do
print_endline (mk_pwd !len !readable)
done