Vigenère cipher: Difference between revisions

Content added Content deleted
(Added Wren)
(New OCaml implementation for >= 4.05)
Line 2,084: Line 2,084:
Code: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
Code: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
Back: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH</pre>
Back: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH</pre>

----

Updated version by [http://rosettacode.org/wiki/User:Vanyamil User:Vanyamil]

This is a custom, more functional version of the existing solution, due to
'''[https://caml.inria.fr/pub/docs/manual-ocaml/libref/String.html OCaml 4.05's unsafe-string compatibility mode]'''

{{works with|OCaml|4.05 or above}}
<lang OCaml>
(* Task : Vigenère_cipher *)

(* This is a custom, more functional version of an existing solution,
due to OCaml 4.05's unsafe-string compatibility mode:
https://caml.inria.fr/pub/docs/manual-ocaml/libref/String.html
*)

(*** Helpers ***)

(* Verbose type abbreviation *)
type key = string

(* Rotate a single uppercase letter *)
let ascii_caesar_shift : bool -> char -> char -> char =
let min_range = Char.code 'A' in
let max_range = Char.code 'Z' in
(* aka 26 but this code can be adapted to larger ranges, such as the ASCII printable range (codes 32 to 126). *)
let range_len = max_range - min_range + 1 in
let actual_fun (dir : bool) (c1 : char) (c2 : char) : char =
let n1 = Char.code c1 in
let n2 = Char.code c2 - min_range in
let sum = (if dir then (+) else (-)) n1 n2 in
( (* Effectively mod function, but simplified and works on negatives. *)
if sum > max_range
then sum - range_len
else if sum < min_range
then sum + range_len
else sum
) |> Char.chr
in
actual_fun

(* Remove non-letters and uppercase *)
let ascii_upper_letters_only (s : string) : string =
let slen = String.length s in
(* Make a list of escaped uppercase letter chars *)
let rec toLetterList sidx acc =
if sidx >= slen
then List.rev acc
else
let c = s.[sidx] in
if c >= 'A' && c <= 'Z'
then toLetterList (sidx + 1) ((c |> Char.escaped) :: acc)
else if c >= 'a' && c <= 'z'
then toLetterList (sidx + 1) ((c |> Char.uppercase_ascii |> Char.escaped) :: acc)
else toLetterList (sidx + 1) acc
in
toLetterList 0 [] |> String.concat ""

(*** Actual task at hand ***)

let vig_crypt (dir : bool) (key : key) (message : string) : string =
let message = ascii_upper_letters_only message in
let key = ascii_upper_letters_only key in
let klen = String.length key in
let aux idx c =
let kidx = idx mod klen in
let e = ascii_caesar_shift dir c key.[kidx] in
e
in
String.mapi aux message

let encrypt : key -> string -> string = vig_crypt true
let decrypt : key -> string -> string = vig_crypt false

(*** Output ***)

let () =
let str = "Beware the Jabberwock, my son! The jaws that bite, \
the claws that catch!" in
let key = "VIGENERECIPHER" in
let ct = encrypt key str in
let pt = decrypt key ct in
Printf.printf "Text: %s\n" str;
Printf.printf "Key: %s\n" key;
Printf.printf "Code: %s\n" ct;
Printf.printf "Back: %s\n" pt
;;
</lang>
{{out}}
<pre>
Text: Beware the Jabberwock, my son! The jaws that bite, the claws that catch!
Key: VIGENERECIPHER
Code: WMCEEIKLGRPIFVMEUGXQPWQVIOIAVEYXUEKFKBTALVXTGAFXYEVKPAGY
Back: BEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCH
</pre>


=={{header|ooRexx}}==
=={{header|ooRexx}}==