Partager via


F# Zen - ROT13

Below is a primitive implementation of ROT13 / Ceasar Cipher in F#. In short it is a simple encryption algorithm that works by 'shifting' each letter 13 places. So an 'a' becomes an 'n', a 'b' becomes an 'o', and so on. To decrypt the text you simply move 13 places in reverse.

We can do this in F# easily using function composition. Given a string, which is also a sequence of characters, we pass it to Array.of_seq so we have an array of characters. This will enable us to replace each character with its encrypted version. Next we map each character to our encryption function, which I'll go over next. Finally, we take our array of encrypted characters and return a new string.

To actually do the encryption, we will compose three functions together. int, will convert the character to its integer representation. "(+) 13" is a curried version of the (+) function, so it adds 13 to its argument. And then we compose that with the char function, which will convert the integer result to a character.

 #light

(**
 * ROT13 in F#
 * 
 * 1. Convert the sequence of chars (string) to an array of chars
 * 2. For each character do the following:
 *    - Convert the character to an integer
 *    - Add 13 to the integer value of the character (by currying (+))
 *    - Convert the integer to a character
 * 3. Create a new string based off the encrypted characters
 *)
 
let EncryptText (text : string) = 
    text
    |> Array.of_seq
    |> Array.map (int >> ((+) 13) >> char)
    |> (fun chars -> new string(chars))

let DecryptText (text : string) = 
    text
    |> Array.of_seq
    |> Array.map (int >> ((+) -13) >> char)
    |> (fun chars -> new string(chars))

let Test message =
    let encrypted = EncryptText message
    let decrypted = DecryptText encrypted

    printfn "Original Message  = %s" message
    printfn "Encrypted Message = %s" encrypted
    printfn "Decrypted Message = %s" decrypted
    
Test "The quick fox jumped over the lazy dog"

Comments

  • Anonymous
    November 07, 2008
    PingBack from http://www.tmao.info/f-zen-rot13/

  • Anonymous
    November 07, 2008
    I like how F# makes the algorithm be so simple and elegant, and I didn't know about this super simple way of casting chars into ints, thanks! I recently made a F# implementation of Bruce Schneier's Solitaire encryption algorithm, you might want to check it out: http://www.sergimansilla.com/blog/?p=24 Your opinion will be really appreciated :) Thanks for your articles!

  • Anonymous
    November 08, 2008
    The comment has been removed

  • Anonymous
    November 09, 2008
    well I guess I give my 25cents too: You will see a lot of ROT13 "encrypted" messages in the usenet (to "hide" a solution, mark a spoiler etc.). In order to make your code really work there you will have to take care of some cases:

  1. normaly only [a-z], [A-Z] gets encrypted so a->n, A->N but !->! for example.
  2. You don't need a decrypt-function in those cases ;) - it's the same as the encryption function
  • Anonymous
    November 10, 2008
    At 13 characters, you're already halfway through the alphabet. Meaning you could have just 1 function for encrypting and decrypting.

  • Anonymous
    November 10, 2008
    @Patrick, True, but if and only if you modulo the integer value of each character with 26. Since I'm blindly adding 13, 'z' becomes something outside the typical ASCII plane... That's exactly why I didn't clame this 'was' an exact implementation of ROT13, but equivocated with 'primitive implementation of ROT13 / Ceasar Cipher'. But yes, you are right. If you did the extra work you would only need one function for encrypting and decrypting.

  • Anonymous
    November 11, 2008
    The comment has been removed

  • Anonymous
    November 11, 2008
    The comment has been removed

  • Anonymous
    November 11, 2008
    The comment has been removed

  • Anonymous
    November 13, 2008
    This doesn't show clever use of function composition (very cool, by the way), but it does provide a traditional rot13 implementation: let rot13 =    let rot b c = (int c - int b + 13) % 26 + int b |> char    String.map (function                 | 'A'..'Z' as c -> rot 'A' c                 | 'a'..'z' as c -> rot 'a' c                 | c -> c )

  • Anonymous
    May 06, 2009
    Summing all cents: let rot13 s =    let rotc = function        | i when 97 <= i && i <= 122 -> (i - 84) % 26 + 97        | i when 65 <= i && i <= 90 -> (i - 52) % 26 + 65        | i -> i    s |> String.map (int >> rotc >> char)

  • Anonymous
    May 06, 2009
    And I do miss python 0 <= x <= 100 construct...