ROT13

February 20, 2009

From the Jargon File:

rot13 /rot ther’teen/ /n.,v./ [Usenet: from `rotate alphabet 13 places'] The simple Caesar-cypher encryption that replaces each English letter with the one 13 places forward or back along the alphabet, so that “The butler did it!” becomes “Gur ohgyre qvq vg!” Most Usenet news reading and posting programs include a rot13 feature. It is used to enclose the text in a sealed wrapper that the reader must choose to open — e.g., for posting things that might offend some readers, or spoilers. A major advantage of rot13 over rot(N) for other N is that it is self-inverse, so the same code can be used for encoding and decoding.

Write a function that takes a string and returns the ROT13 version of the string; you may assume that the character set is ascii. What is the meaning of “Cebtenzzvat Cenkvf vf sha!”

About these ads

Pages: 1 2

25 Responses to “ROT13”

  1. Dan Schoch said

    This is a rather trivial exercise for Oracle’s PL/SQL since it has a TRANSLATE function. This function translates each character in a given string using “from” and “to” positional strings, passed as parameters (along with the target string, of course). Each character in the target string found in the “from” string is replaced by the corresponding character in the “to” string. Quite handy, especially for doing ROT13. But as you can see, I only included a couple of special characters in the translation strings, so my first implementation was rather limited:

        function rot13(parm_str in varchar2) return varchar2 is
        begin
            return translate(parm_str,
                             'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.,!?',
                             'NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm.,!?') ;
        end rot13 ;
    

    Rather than adding all the non-alphabetics I could type, I decided to write my own simple translation logic to handle any ASCII character:

        function rot13(parm_str in varchar2) return varchar2 is
            j               pls_integer ;
            parm_ret        varchar2(1000) := null ;
        begin
            for i in 1..length(parm_str)
            loop
                j := ascii(substr(parm_str,i,1)) ;
                case
                    when j>=65 and j<=90    /* A-Z */
                    then j:=j-13 ;
                         if j<65 then j:=j+26; end if ;
                    when j>=97 and j<=122   /* a-z */
                    then j:=j-13;
                         if j<97 then j:=j+26; end if ;
                    else null ;
                end case ;
                parm_ret := parm_ret||chr(j);
            end loop ;
            return parm_ret ;
        end rot13 ;
    

    Simple, but it works.

  2. mnp said

    Not too hard in perl:

    y/A-Za-z/N-ZA-Mn-za-m/;

  3. snowbeard said

    import Maybe (fromMaybe)
    import Data.List (find)

    genTab :: Int -> [(Char, Char)]
    genTab rot = zip (['a'..'z'] ++ ['A'..'Z']) (take 26 (drop rot (cycle ['a'..'z'])) ++
    take 26 (drop rot (cycle ['A'..'Z'])))

    {- apply the cipher function to the string. It substitutes values obtained from the
    lookup table, generated by the function genTab -}
    rotFunc :: Int -> String -> String
    rotFunc rot str = map cipher str
    where cipher c = (snd (fromMaybe (c,c) (find (\ x -> (fst x) == c) (genTab rot))))

    rot13 :: String -> String
    rot13 = rotFunc 13

  4. FalconNL said

    Alternative Haskell approach:

    import Data.Map (findWithDefault, fromList)
    
    main = print $ map rot13 "Cebtenzzvat Cenkvf vf sha!"
    
    rot13 :: Char -> Char
    rot13 c = findWithDefault c c . fromList $ zip (['A'..'Z'] ++ ['a'..'z'])
    	(shift 13 ['A'..'Z'] ++ shift 13 ['a'..'z'])
    
    shift :: Int -> [a] -> [a]
    shift n xs = drop n xs ++ take n xs
    
  5. ksson said

    My OCaml version.

    let rot13 s = 
      let rotate c = 
        let aux i = char_of_int ( i + (int_of_char c - i + 13) mod 26) in
        match c with
        | 'A'..'Z' -> aux 65
        | 'a'..'z' -> aux 97
        | _ -> c
      in
      for i = 0 to String.length s - 1 do s.[i] <- rotate s.[i] done
    
    let _ = 
      let s = "Cebtenzzvat Cenkvf vf sha!" in
      rot13 s; print_endline s
    
  6. Nikhil said

    Very simple python solution, but makes everything lowercase

    from string import ascii_lowercase, maketrans, translate
    def rot13(s):
        return translate(s.lower(), maketrans(ascii_lowercase, ascii_lowercase[13:] + ascii_lowercase[:13]))
    
  7. N. said
    def rotate(ox, base):
        return chr(base + ((ox - base) + 13) % 26)
    
    def handle(x):
        ox = ord(x)
        if ord("a") <= ox and ox <= ord("z"):
            return rotate(ox, ord("a"))
        elif ord("A") <= ox and ox <= ord("Z"):
            return rotate(ox, ord("A"))
        else:
            return x
    
    def rot13(input):
        return "".join(map(handle, input))
    

    >>> rot13(“Cebtenzzvat Cenkvf vf sha!”)
    ‘Programming Praxis is fun!’

  8. Colin said

    A solution in SML.

    (* ROT13 cipher *)
    (* see: http://programmingpraxis.com/2009/02/20/rot13/ *)

    fun rot13 (str : string) : string =
      let
        fun wrapTo (ch : char, top : char) : char =
          let
            val next = Char.ord ch + 13
          in
            if next > Char.ord top then
              Char.chr (next – 26)
            else
              Char.chr (next)
          end

        fun rotChar (ch : char) : char =
          if ch >= #”a” andalso ch <= #”z” then
            wrapTo (ch, #”z”)
          else if ch >= #”A” andalso ch <= #”z” then
            wrapTo (ch, #”Z”)
          else
            ch
      in
        String.map rotChar str
      end

  9. slabounty said

    Thought this would be nice in ruby …

    class String
        def rot13
            self.tr('A-Za-z.!(),', 'N-ZA-Mn-za-m.!(),')
        end
    end
    
    # Should print Programming Praxis is fun!
    puts "Cebtenzzvat Cenkvf vf sha!".rot13
    

    Adding rot13 to the String class makes it available for all Strings. Kind of a nice feature.

  10. Python – a more functional & less readable approach:

    from string import letters
    from string import lowercase
    from string import uppercase
    
    def get_shifted(text, numlet=26, num=13):
        shift = lambda x: (x + num) % numlet
        llist = lambda let : [[let[x], let[shift(x)]] for x in range(numlet)]
        shifted = dict(llist(uppercase) + llist(lowercase))
        return "".join([shifted[s] if s in letters else s for s in text]) 
    
    if __name__ == '__main__':
        print get_shifted("Cebtenzzvat Cenkvf vf sha!")
    
  11. [...] this ProgrammingPraxis challenge we have to build a simple Caesar Cipher variant called rot13 [...]

  12. Jebb said
    def rot13(text):
    	from string import ascii_letters, maketrans, translate
    	intab = ascii_letters
    	outtab = intab[13:26] + intab[:13] + intab[39:] + intab[26:39]
    	map = maketrans(intab, outtab)
    	print translate(text, map)
    
  13. egross73 said

    This is probably much longer than it has to be, but here is my solution in python:

    alpha = {
    ‘a’:'n’,
    ‘b’:'o’,
    ‘c’:'p’,
    ‘d’:'q’,
    ‘e’:'r’,
    ‘f’:'s’,
    ‘g’:'t’,
    ‘h’:'u’,
    ‘i’:'v’,
    ‘j’:'w’,
    ‘k’:'x’,
    ‘l’:'y’,
    ‘m’:'z’,
    ‘n’:'a’,
    ‘o’:'b’,
    ‘p’:'c’,
    ‘q’:'d’,
    ‘r’:'e’,
    ‘s’:'f’,
    ‘t’:'g’,
    ‘u’:'h’,
    ‘v’:'i’,
    ‘w’:'j’,
    ‘x’:'k’,
    ‘y’:'l’,
    ‘z’:'m’}

    txt = input(‘Text to cypher with rot13: ‘)

    txtlst = list(txt)
    count = 0

    while count < len(txtlst):
    let = txtlst[count]
    txtlst[count] = alpha[let]
    count+=1

    rotd = "".join(txtlst)
    print(txt+" becomes "+rotd)

  14. Robert said

    Tcl

    #
    # Gives a version that doesn’t require any additional procedures, and rotates by any amount (specified by an optional second argument,
    # defaults to 13 of course) — And supports negative rotation amounts
    #
    proc rot {text {amount 13}} {
    if {abs($amount) > 25} {
    set amount [expr {$amount % 26}]
    }

    set alphabet “ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz”
    set res “”
    set length [string length $text]
    set find_command [expr {$amount > 0 ? "first" : "last"}]

    for {set index 0} {$index < $length} {incr index} {
    set char [string index $text $index]
    set pos [string $find_command $char $alphabet]
    append res [expr {$pos == -1 ? $char : [string index $alphabet [expr {$pos + $amount}]]}]
    }
    return $res
    }

  15. Calvin Ference said

    #!/usr/bin/env python

    def ROT13(plain):
    cypher = ”

    for char in plain:
    if char.isalpha():
    raw = ord(char)

    if raw in range(97,110) or raw in range(65,78):
    char = chr(raw+13)
    else:
    char = chr(raw-13)

    cypher = cypher + char
    return cypher

    if __name__ == ‘__main__’:
    print ROT13(‘Cebtenzzvat Cenkvf vf sha!’)

  16. And here is my example in Python:

    shift = 13
    def rot13(mystr):
      smallZ = ord('z')
      bigZ = ord('Z')
    
      strOrdLst = map(ord, mystr)
      strDict = zip(mystr, strOrdLst)
      res = ''
      for key, value in strDict:
        if key.isupper():
          if value + shift > bigZ:  
            res += chr(value - shift)
          else:
            res += chr(value + shift)
        elif key.islower():
          if value + shift > smallZ:  
            res += chr(value - shift)
          else:
            res += chr(value + shift)
        else:
          res += key 
      return res 
    
    print(rot13('Cebtenzzvat Cenkvf vf sha!'))
    
  17. My version in Haskell:

    import Data.Char
    
    rot13 :: String -> [Int]
    rot13 [x] = if (ord x) < 110
                   then (map (\x -> (x + 13)) [ord x])
    			   else (map (\x -> (x - 13)) [ord x])
    rot13 (x:xs) =  rot13 [x] ++ rot13 xs
    
    solution :: String -> String
    solution [x] = map (\x -> chr x) (rot13 [x])
    solution (x:xs) = solution [x] ++ solution xs
    
  18. GoLang

    func rot13(s string) string {
    	return strings.Map(func(c rune) rune {
    		switch {
    		case unicode.IsLetter(c + ROT):
    			return c + ROT
    		case unicode.IsLetter(c - ROT):
    			return c - ROT
    		}
    		return c
    	}, s)
    }
    
    
  19. j0sejuan said

    golang

    package main
    
    import (
    	"fmt"
    	"strings"
    )
    
    func rot13r(r rune) rune {
    	if x := strings.IndexRune("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", r); x >= 0 {
    		return rune("NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm"[x]);
    	}
    	return r
    }
    
    func rot13(s string) string {
    	return strings.Map(rot13r, s)
    }
    
    func main() {
    	fmt.Printf("%s\n", rot13("Cebtenzzvat Cenkvf vf sha!"))
    }
    
  20. jgarcia1f said

    Java solution:

    //ROT 13 function
    String input = "Cebtenzzvat Cenkvf vf sha!";
    String output = new String();
    	
    for(int i = 0; i < input.length(); i++){
    	char ch = input.charAt(i);
    	if(Character.isLetter(ch)){
    		if(Character.toLowerCase(ch) > 'm'){
    			ch -= 13;
    		}else
    			ch += 13;
    	}
    	
    	output = output.concat(String.valueOf(ch));
    }
    
    System.out.println("In:  " + input);
    System.out.println("Out: " + output);
    
  21. Noah said

    Python. Not sure about efficiency, but I got to play with strings.

    import string

    def rot13(input):
    shift = 13
    lst = list(input)
    c = 0
    while c = 97 and i = 65 and i <= 90 : # [A-Z]
    lst[c] = (chr(( i-65-shift)%26 + 65))
    c += 1
    return ''.join(map(''.join,lst))

    print(rot13('The butler did it!')) # Gur ohgyre qvq vg!

  22. Noah said

    Python, also attempting to format correctly… sorry for double post.

    import string
    
    def rot13(input):
        shift = 13
        lst = list(input)
        c = 0
        while c < len(lst):
            i = ord(lst[c])
            if i >= 97 and i <= 122: # [a-z]
                lst[c] = (chr( (i-97-shift)%26 + 97))
            if i >= 65 and i <= 90 : # [A-Z]
                lst[c] = (chr(( i-65-shift)%26 + 65)) 
            c += 1
        return ''.join(map(''.join,lst))
        
    print(rot13('The butler did it!')) # Gur ohgyre qvq vg!
    

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 469 other followers

%d bloggers like this: