I was looking through the "beginner projects" looking for a way to use dictionaries so I could understand them better. I saw the caesar cipher suggestion and decided to run with that. I created a working one, but (as I saw in the "If...else") just because something works doesn't mean it uses good techniques and is efficient. I saw that Jeff's code was much better--I like the use of dictionaries. So, here's my program. I'd love for you to point out all the bad things about it and help me improve the code (and my techniques).

alphabet = "abcdefghijklmnopqrstuvwxyz"

def encode(words):
    encode = {'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'}
    new_words = ""
    for letter in words:
        if letter in alphabet:
            new_words = new_words + encode[letter]
            continue
        new_words = new_words + letter
    return new_words

def decode(words):
    decode = {'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', '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'}
    new_words = ""
    for letter in words:
        if letter in alphabet:
            new_words = new_words + decode[letter]
            continue
        new_words = new_words + letter
    return new_words

menu = """
(1) Encode
(2) Decode
(3) What's ROT-13?
(4) Quit
    """
choice = 0
end = 0

print "Welcome to Mouche's ROT-13 Encoder/Decoder"
while end != 1:
    str1 = ""
    str2 = ""
    print menu
    while choice < 1 or choice > 4:
        choice = raw_input("What would you like to do? ")
        try:
            choice = int(choice)
        except ValueError:
            print "Please choose an option on the menu (number)."
    if choice == 1 or choice == 2:
        str1 = raw_input("Message: ").lower()
    if choice == 1:
        str2 = encode(str1)
        print "This is your message after being encoded."
        print str2
        raw_input("Enter to continue")
    if choice == 2:
        str2 = decode(str1)
        print "This is your message after being decoded."
        print str2
        raw_input("Enter to continue")
    if choice == 3:
        print "\nROT-13 is a common caesar cipher. It is encoded by rotating the letters in a message 13 places. Ex: the letter 'a' would be 'n'"
        raw_input("Enter to continue")
    if choice == 4:
        print "Thanks for using Mouche's ROT-13 Encoder/Decoder."
        end = 1
    choice = 0

Thanks.

you can use maketrans and translate to create the lookup table

eg usage

import string
letters = string.ascii_lowercase
key = 13
trans_table = letters[key:] + letters[0:key]
trans = string.maketrans(letters,trans_table)
text = "i am crazy"
print text.translate(trans)

output:

'v nz penml'

For newer version of Python, there is encode() method

text.encode('rot13')

Let's return for a moment to the original endeavor on LaMouche's part to learn about dictionaries.

Notice that your encode and decode dictionaries are the same. The order of the keys will be decided internally by the dictionary anyway using a hash algorithm to speed up key searches.

You could create the dictionary with a for loop this way:

def create_rotdic(rot=13):
    encode = {}
    for x in range(ord('a'), ord('z')+1):
        c = chr(x)
        limit = ord('z') - rot
        # past the limit start with 'a' 
        if x <= limit:
            ascii_val = ord(c) + rot
        else:
            ascii_val = ord(c) - rot
        encode[c] = chr(ascii_val)
    return encode
    

encode = create_rotdic()
print encode

That also would allow you to rotate by something other than 13 positions, just to be tricky!

Ghostdog's reminder that there is a builtin encode() method is sweet however:

# uses rot13 encoding
# alphabet is shifted by 13 positions to "nopqrstuvwxyzabcdefghijklm"
# so original 'a' becomes 'n' and so on
text = "i am crazy"
print "original =", text
encoded = text.encode('rot13')
print "encoded  =", encoded
decoded = encoded.encode('rot13')
print "decoded  =", decoded

Not much to do with dictionaries, but you learned something new!

Ghostdog also showed how to create the alphabet string a little simpler:

import string
alphabet = string.ascii_lowercase

# test
print alphabet  # abcdefghijklmnopqrstuvwxyz

Thanks a lot. Could you explain this part a bit more?

# past the limit start with 'a'  
        if x <= limit: 
            ascii_val = ord(c) + rot 
        else: 
            ascii_val = ord(c) - rot

I understand that ord() gets you the ascii value, but I'm not understanding the logic with the + rot and - rot.

Thanks a lot. Could you explain this part a bit more?

# past the limit start with 'a'  
        if x <= limit: 
            ascii_val = ord(c) + rot 
        else: 
            ascii_val = ord(c) - rot

I understand that ord() gets you the ascii value, but I'm not understanding the logic with the + rot and - rot.

"rot" is just the parameters defined in the function, and what is happening is it's being added to the value of whatever character the iteration is on.

So therefore, let's say the word is "apple" and the letter is on "a"
a has an ASCII value of 97, we are shifting 13 places in the alphabet to the right.

Thus we end up with 110, or n.

That's a very creative yet simple approach, and makes the shift amount variable, I like it very much. :)

yes, I understand that part. What I'm unclear on is the else part of that block.

I simplified the code a little and put in test prints, hopefully that will explain the logic of the loop-around:

# loop around alphabet, offset/rotated by 13

rot = 13
for x in range(ord('a'), ord('z')+1):
    c = chr(x)
    limit = ord('z') - rot    
    # past the limit start with 'a'
    if x <= limit: 
        ascii_val = ord(c) + rot
        print chr(ascii_val),  # test print
    else: 
        ascii_val = ord(c) - rot
        print chr(ascii_val),  # test print

"""
note when the 'z' is reached how it restarts with 'a':
n o p q r s t u v w x y z a b c d e f g h i j k l m
"""
This article has been dead for over six months. Start a new discussion instead.