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

34 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!
    
  23. Reblogged this on graveborn and commented:
    The following is the source code to my solution to the 6th problem – “ROT13: A simple Caesar-shift cipher” – of Programming Praxis, and my first program for the Amstrad Plus.

    I don’t know if the additional features of the Amstrad Plus are accessible through CP/M and Pascal, but my goal when programming the following solution was merely to gain a little familiarity with using the Amstrad Plus, eg. a familiarity with editing, saving, and loading text files, and erasing files.

    PROGRAM ROT13;
    
    CONST
      kMaxStringLength = 80;
    
    TYPE
      String = RECORD
        l : 0..kMaxStringLength;
        s : ARRAY [ 1..kMaxStringLength ] OF CHAR
      END;
    
    VAR
      gS : String;
      i : 1..kMaxStringLength;
      c : CHAR;
      uppercase : BOOLEAN;
      cI : INTEGER;
    
    PROCEDURE ReadString( VAR p : String );
    BEGIN
      p.l := 0;
      REPEAT
        p.l := p.l + 1;
        READ( p.s[ p.l ] )
      UNTIL EOLN OR ( p.l = kMaxStringLength )
    END;
    
    PROCEDURE WriteString( p : String );
    VAR
      i : 1..kMaxStringLength;
    BEGIN
      FOR i := 1 TO p.l DO
        WRITE( p.s[ i ] )
    END;
    
    FUNCTION ToLowercase( p : CHAR ) : CHAR;
    VAR
      i : INTEGER;
    BEGIN
      IF p IN [ 'A'..'Z' ] THEN BEGIN
        i := ORD( p ) - ORD( 'A' );
        i := i + ORD( 'a' );
        p := CHR( i )
      END;
      ToLowercase := p
    END;
    
    BEGIN
      WRITELN;
      WRITELN( '* ROT13 by graveborn' );
      WRITELN( '* <http://thegraveborn.wordpress.com/>' );
      WRITELN( '***' );
      WRITELN( '* Enter a string to ROT13 and press the Return key;' );
      WRITELN( '* or enter nothing and press the Return key to quit.' );
      WRITELN( '***' );
      WRITELN;
      WRITE( ' :' );
      ReadString( gS );
      WHILE gS.l > 1 DO BEGIN
        FOR i := 1 TO gS.l DO BEGIN
          c := gS.s[ i ];
          uppercase := c IN [ 'A'..'Z' ];
          c := ToLowercase( c );
          IF c IN [ 'a'..'z' ] THEN BEGIN
            cI := ORD( c ) - ORD( 'a' );
            cI := cI + 1;
            (* ^ So 'a' = 1, not 0 *)
            cI := cI + 13;
            IF cI > 26 THEN
              cI := cI - 26;
            cI := cI - 1;
            (* ^ So 'a' = 0, not 1 *)
            IF NOT uppercase THEN
              cI := cI + ORD( 'a' )
            ELSE
              cI := cI + ORD( 'A' );
            c := CHR( cI )
          END;
          WRITE( c )
        END;
        WRITELN;
        WRITE( ' :');
        ReadString( gS )
      END
    END.
  24. […] Reblogged from Programming Praxis: […]

  25. […] following is the source code to my solution to the 6th problem – “ROT13: A simple Caesar-shift cipher” – of Programming Praxis, and my first program for the […]

  26. Roberto Bravo said
    import string
    from string import maketrans
    
    text = "Cebtenzzvat Cenkvf vf sha!"
    text = text.lower()
    
    table = string.maketrans(string.ascii_lowercase,string.ascii_lowercase[13:]+string.ascii_lowercase[:13])
    
    print text.translate(table)
    
  27. Roberto Bravo said

    Sorry for double post i’m trying to highlight my code correctly

    import string
    from string import maketrans
    
    text = "Cebtenzzvat Cenkvf vf sha!"
    text = text.lower()
    
    table = string.maketrans(string.ascii_lowercase,string.ascii_lowercase[13:]+string.ascii_lowercase[:13])
    
    print text.translate(table)
    
  28. Dan said

    My C++ version:

  29. Dan said

    My C++ version:

    #include <iostream>
    #include <string>
    #include <cctype>

    using namespace std;

    void getUserInput(string &strUserInput)
    {
    cout<< "Enter your text: " << endl;
    getline(cin, strUserInput);
    }

    void ROT13(string &strUserInput, string &strResult)
    {
    for (auto it = strUserInput.begin(); it != strUserInput.end(); ++it)
    {
    if (isspace(*it) || ispunct(*it))
    strResult += *it;
    else
    {
    if (isupper(*it))
    {
    if (*it + 13 <= ‘Z’)
    strResult += (*it + 13);
    else
    strResult += (*it – 13);
    }
    else
    {
    if (*it + 13 <= ‘z’)
    strResult += (*it + 13);
    else
    strResult += (*it – 13);
    }
    }
    }
    }

    int main()
    {
    string strUserInput, strResult;

    getUserInput(strUserInput);
    ROT13(strUserInput, strResult);

    cout<< "The result text is: " << strResult << endl;

    cin.get();
    return 0;
    }

  30. Manio143 said

    My small version in C++ :

    #include
    std::string Rot13(std::string Input)
    {
    int i;
    for(i=0; i = 65 && Input[i] = 97 && Input[i] = 78 && Input[i] = 110 && Input[i] <= 122))
    Input[i] -= 13;
    }
    return Input;
    }

  31. William said

    Learning to Scala! A copy off of my worksheet:

    object Rot {
      
      def rot13( text: String ): String = {
      	
      	val uppercase = new Range( 65, 90,  1 )
      	val lowercase = new Range( 97, 122, 1 )
      	
      	def modAdd( a: Int, b: Int, max: Int, size: Int ): Int =
      		if( (a + b) > max ) a+b-size
      		else (a+b)
      	
      	def iter( in: String, acc: String ): String =
      		if( in.isEmpty ) acc
      		else if ( uppercase.contains(in.charAt(0)) ) iter( in.substring(1), acc+modAdd( in.charAt(0).toInt, 13, 90,  26).toChar )
      		else if ( lowercase.contains(in.charAt(0)) ) iter( in.substring(1), acc+modAdd( in.charAt(0).toInt, 13, 122, 26).toChar )
      		else iter( in.substring(1), acc+in.charAt(0) )
      	iter( text, "" )
      }                                               //> rot13: (text: String)String
      
      rot13(rot13("THISIS A TEST!!!"))                //> res0: String = THISIS A TEST!!!
      rot13("HEYHEYHEYHEY")                           //> res1: String = URLURLURLURL
      rot13("!!!@@#!@")                               //> res2: String = !!!@@#!@
      }
    

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 )

Google+ photo

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

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 600 other followers

%d bloggers like this: