Rot13 (Python)

From LiteratePrograms

Jump to: navigation, search
Other implementations: Forth | Haskell | Java | Python | Scheme | Sed

This is an implementation of Rot13, a simplistic shift cipher. The goal is thus to introduce Python functionality in a semi-practical setting.


Transposing individual characters

Since the algorithm works on individual characters of the string, we'll first write a function that transposes a single character. Python itself does not have a special type for characters -- they are just strings of length 1.

First, test if the character is alphabetical -- we only want to transpose alphabetical characters. Numbers, whitespace, and any other character remains unchanged.

if not ch.isalpha():
  return ch

Next, rather than dealing with uppercase and lowercase characters separately, we'd first force the character to lowercase. Making it uppercase works equally well. Now that we know the character is both alphabetic and lowercase, the only question is whether it is one of the first 13 characters in the alphabet, in which case it can be shifted to the right by 13 places, or the last 13 characters, in which case it is shifted to the left.

Unlike languages in the C family (C/C++/Obj-C/Java/C#), in Python you cannot do arithmetic on characters (recall that Python does not even have a real character type!). You'd need to first get the ordinal value of the character, using ord, perform the arithmetic operation on the resulting integer, and then get the character corresponding to this new ordinal value, using chr.

Rather than writing this code twice, which introduces the risk of the two being out of sync, here we compute the shift distance once -- this varies depending on the character being transposed -- and then use this distance in computing the new character.

def rot13_char(ch):
  ch_low = ch.lower()
  if ch_low <= 'm':
    dist = 13
    dist = -13
  return chr(ord(ch) + dist)

Transposing a string

Once the function for transposing a single character is written, transposing an entire string is simplicity itself. Using Python's generator expression, we decompose the input string into its individual characters, make a generator that outputs the result of transposing each using rot13_char, and then join the characters back into a string using join.

def rot13(s):
  return ''.join( rot13_char(ch) for ch in s )

I/O and exception handling

Next we'd need a way to interact with users. The while loop below would keep reading a single line of input, calculating the transposition, and printing it out.

Users can terminate the session by using the standard CTRL-C, which will raise a KeyboardInterrupt exception; this is caught outside the loop, at which point we print a parting message and the program terminates.

#!/usr/bin/env python
if __name__ == '__main__':
    while True:
      print rot13(raw_input())
  except KeyboardInterrupt:
      print 'Bye!'
Download code