Question

After much frustration, I have made my first Caesar Decoder :)

But the problem now is to make the program circular...

For example if we want to shift doge by 1, no problem, it's ephf...

But what about xyz, and the shift was 4???

So programming pros help a first time novice aka newb out :P Thanks...

import string
def main():        
    inString = raw_input("Please enter the word to be "
                         "translated: ")
    key = int(raw_input("What is the key value? "))

    toConv = [ord(i) for i in inString] #now want to shift it by key
    toConv = [x+key for x in toConv]
    #^can use map(lambda x:x+key, toConv)
    result = ''.join(chr(i) for i in toConv)

    print "This is the final result due to the shift", result
Was it helpful?

Solution

Just add the key to all the actual character codes, then if the added value is greater than z, modulo with character code of z and add it with the character code of a.

inString, key = "xyz", 4
toConv = [(ord(i) + key) for i in inString] #now want to shift it by key
toConv = [(x % ord("z")) + ord("a") if x > ord("z") else x for x in toConv]
result = ''.join(chr(i) for i in toConv)
print result   # cde

OTHER TIPS

I'd recommend using string.translate().

So, we can do the following:

key = 1
table = string.maketrans(string.ascii_lowercase + string.ascii_uppercase, string.ascii_lowercase[key:] + string.ascii_lowercase[:key] + string.ascii_uppercase[key:] + string.ascii_uppercase[:key])

And then we can use it as follows:

'doge'.translate(table) # Outputs 'ephf'
'Doge'.translate(table) # Outputs 'Ephf'
'xyz'.translate(table)  # Outputs 'yza'

In particular, this doesn't change characters that are not ascii lowercase or uppercase characters, like numbers or spaces.

'3 2 1 a'.translate(table) # Outputs '3 2 1 b'

in general, to make something "wrap" you use the modulo function (% in Python) with the number you want to wrap, and the range you want it to wrap in. For example, if I wanted to print the numbers 1 through 10 a bajillion times, I would do:

i = 0
while 1:
    print(i%10+1)
    # I want to see 1-10, and i=10 will give me 0 (10%10==0), so i%10+1!
    i += 1

In this case it's a little more difficult because you're using ord, which doesn't have a nice happy "range" of values. If you had done something like string.ascii_lowercase you could do...

import string
codex = string.ascii_lowercase

inString = "abcdxyz"
key = 3
outString = [codex[(codex.index(char)+key)%len(codex)] for char in inString]

However since you're using ord, we're kind of going from ord('A') == 65 to ord('z')==122, so a range of 0 -> 57 (e.g. range(58), with a constant of 65. In other words:

codex = "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz"
# every char for chr(65) -> chr(122)

codex = ''.join([chr(i+65) for i in range(58)]) # this is the same thing!

we can do this instead, but it WILL include the characters [\]^_`

inString, key = 'abcxyzABCXYZ', 4
toConv = [(ord(i)+key-65)%58 for i in inString]
result = ''.join(chr(i+65) for i in toConv)
print(result)
# "efgBCDEFG\\]^"

Here is Python code that I wrote to be easy to understand. Also, I think the classic Caesar cipher didn't define what to do with punctuation; I think the classic secret messages were unpunctuated and only contained letters. I wrote this to only handle the classic Roman alphabet and pass any other characters unchanged.

As a bonus, you can use this code with a shift of 13 to decode ROT13-encoded jokes.

def caesar_ch(ch, shift):
    """
    Caesar cipher for one character.  Only shifts 'a' through 'z'
    and 'A' through 'Z'; leaves other chars unchanged.
    """
    n = ord(ch)
    if ord('a') <= n <= ord('z'):
        n = n - ord('a')
        n = (n + shift) % 26
        n = n + ord('a')
        return chr(n)
    elif ord('A') <= n <= ord('Z'):
        n = n - ord('A')
        n = (n + shift) % 26
        n = n + ord('A')
        return chr(n)
    else:
        return ch

def caesar(s, shift):
    """
    Caesar cipher for a string.  Only shifts 'a' through 'z'
    and 'A' through 'Z'; leaves other chars unchanged.
    """
    return ''.join(caesar_ch(ch, shift) for ch in s)

if __name__ == "__main__":
    assert caesar("doge", 1) == "ephf"

    assert caesar("xyz", 4) == "bcd"

    assert caesar("Veni, vidi, vici.", 13) == "Irav, ivqv, ivpv."

The part at the end is a "self-test" for the code. If you run this as a stand-alone program, it will test itself, and "assert" if a test fails.

If you have any questions about this code, just ask and I'll explain.

I know this is kind of an old topic, but I just happened to be working on it today. I found the answers in this thread useful, but they all seemed to use a decision to loop. I figured a way to accomplish the same goal just using the modulus(remainder) operator (%). This allows the number to stay within the range of a table and loop around. It also allows for easy decoding.

# advCeaser.py
# This program uses a ceaser cypher to encode and decode messages
import string

def main():
    # Create a table to reference all upper, lower case, numbers and common punctuation.
    table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz1234567890,.!?-@'

    print 'This program accepts a message and a key to encode the message.'
    print 'If the encoded message is entered with the negative value of the key'
    print 'The message will be decoded!'

    # Create accumulator to collect coded message 
code =''

    # Get input from user: Message and encode key
    message = raw_input('Enter the message you would like to have encoded:')
    key = input('Enter the encode or decode key: ')

    # Loop through each character in the message
    for ch in message:
        # Find the index of the char in the table add the key value
        # Then use the remainder function to stay within range of the table.
        index = ((table.find(ch)+key)%len(table))

        # Add a new character to the code using the index
        code = code + table[index]

    # Print out the final code
    print code

main()

The encode and decode output look like this.

encode:

This program accepts a message and a key to encode the message.
If the encoded message is entered with the negative value of the key
The message will be decoded!
Enter the message you would like to have encoded:The zephyr blows from the east to the west!
Enter the encode or decode key: 10
croj0ozr92jlvy73jp2ywj4rojok34j4yj4roj7o34G

decode:

This program accepts a message and a key to encode the message.
If the encoded message is entered with the negative value of the key
The message will be decoded!
Enter the message you would like to have encoded:croj0ozr92jlvy73jp2ywj4rojok34j4yj4roj7o34G
Enter the encode or decode key: -10
The zephyr blows from the east to the west!

Sorry if my formatting looks catywompus I literally found stackoverflow yesterday! Yes, I literally mean literally :)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top