Hello. I was wondering if anyone could help me with a caesar cipher program I am attempting to create. I was asked to write a caesar cipher encoder program. Ok. No problem. This is what i got:

import string
def main():
    print "This program will encode your messages using a Caesar Cipher"
    print
    key = input("Enter the key: ")
    message = raw_input("Enter the message: ")
    codedMessage = ""
    for ch in message:
            codedMessage = codedMessage + chr(ord(ch) + key)
    print "The coded message is:", codedMessage
 
main()

This works fine. But then I am asked to modify it to make it circular, where after "z" it will return to "a". I am at a loss for how to do this. This is probably a stupid question, but I am a beginner to Python and desperately need assistance. Please help. Thanks.

Recommended Answers

All 13 Replies

That's a good start. I might do something like

...
for ch in message:
    code_val  = ord(ch) + key
    if code_val > ord('z'):
        code_val -= 26  # better: ord('z') - ord('a'), just in case len(alphabet) != 26
    codedMessage = codedMessage+chr(code_val)
...

Jeff

Thanks. That really helps. Would there also be a way for me to make it so non-alphabetic characters (spaces, punctuation, etc.) do not change with the rest of the text?

...
for char in message:
    # check if the character is alphabetic
    if char.isalpha():
        ...

Regards, mawe

Sounds interesting, so i put it all together:

message = "just a simple test!"
key = 11
coded_message = ""
for ch in message:
    code_val  = ord(ch) + key
    if ch.isalpha():
        if code_val > ord('z'):
            code_val -= ord('z') - ord('a')
        coded_message = coded_message + chr(code_val)
    else:
        coded_message = coded_message + ch
print message
print coded_message

-- and I get this:

just a simple test!
ugef l etxbwp fpef!

-- great, but how can I get the original message back?

Well, what you're trying to do is invert the function that got you there to begin with. See if you can decode a couple of examples by hand and then go from there.

Jeff

Thanks so much everyone! That makes the program look so much better. I think I may be starting to understand this a little better.

I'm working on the same program, just modified slightly. Instead of printing the results, I'm writing them (and reading the input) from a .txt file. Unfortunatly, with a .txt file, it automatically adds a "\n" character at the end of each line. After running the program and opening the encoded message, there's an extra character at the end of the message. How can I pick that one character off?
Thanks so much!

def main():
    
    # gets user input to encode or decode
    decision = raw_input("Enter 1 to encode a message, and 2 to decode a message. ")
    
    if int(decision) == 1:      # starts encoding process if user enters 1
        
        # creates files for reading and writing to
        infile = open("plaintext.txt", "r")
        outfile = open("ciphertext.txt", "w")

        data = infile.read()
        key = int(data[0])      # "picks off" the shift key value from the text file and makes into an integer
        
        message = data[1:]      # slices off the shift key number to leave only the message to be encoded
        encrypted_message = ""

        # creates a loop that goes through each character in the string
        # and adds the shift key value to that character's ascii value,
        # then turns each of those ascii values back into a character
        for i in message:
            letter_value = ord(i) + key
            if letter_value > ord("z"):
                letter_value -= ord("z") - ord("a") + 1
            encrypted_message = encrypted_message + chr(letter_value)

        outfile.write(str(key))   # makes the key value a string and then writes to file
        outfile.write(encrypted_message)    # writes encrypted message to file

        infile.close()      # closes infile
        outfile.close()     # closes outfile
s = "abcdefg\n"

print s
print '-'*10

# strip off trailing '\n' char
s = s.rstrip('\n')

print s
print '-'*10
Member Avatar for soUPERMan

Sounds interesting, so i put it all together:

message = "just a simple test!"
key = 11
coded_message = ""
for ch in message:
    code_val  = ord(ch) + key
    if ch.isalpha():
        if code_val > ord('z'):
            code_val -= ord('z') - ord('a')
        coded_message = coded_message + chr(code_val)
    else:
        coded_message = coded_message + ch
print message
print coded_message

-- and I get this:

just a simple test!
ugef l etxbwp fpef!

-- great, but how can I get the original message back?

Sorry im a n00b, would like to know that the for-loop does. Thanks :)

To:
soUPERMan

Solved threads are not a good media to ask questions. Many folks think the thread is solved and don't even look. So, if you have a question, start your own thread and title it properly.

Hello everyone!

I ask you guys to try large positives and negatives with your code. It does not seem to work for me!

Zelle wants us to create a circular Caesar Cipher, so all numbers should be legitimate entries as long as they are integers (which you can force with int())

What follows are two solutions I came up with (in Python 3.1). Both use the "remainder %" operation. The first uses a encryption character list so that we can choose which characters we want to be affected The second affects all characters. These two methods should work for any encryption key value - positive or negative. Good luck!

# title:    circular_caesar_cipher.py
# version:  PYTHON 3.1
# date:     2010-03-08
# author:   Jamie Ghassibi
# contact:  jghassibi@gmail.com
#
# This program usesthe "remainder %" operator to create a circular
#Caesar Cipher.


# CREATE ENCRYPTION CHARACTER STRING
#
# 1. Create a tuple (a_ranges) filled with the desired ascii ranges.
#
# Note: This list of ranges corresponds to the ascii codes for certain
#characters, such as mathmatical operators and numbers (39-57),
#uppercase letters (65-90), and lowercase letters (97-123). Also note
#that if you only include one range, there will be an error because
#i_range will ignore the fact that it is dealing with elements in a
#tuple. #The solution - if you want to include only one range - is to
#write:
#   a_ranges = (range(start,end),)
#This will still tell the for loop that it is dealing with a tuple.
#
# Note: Creating an encryption character string allows me specify
#which characters I want to change or not change during encryption.
#More importantly, this method allows me to create a _circular_ Caesar
#Cipher using the "remainder %" operation as I will explain later.
#
# 2. Create an empty string (e_string), to accumulate the characters
#for the encryption string.
#
# 3. The first for loop goes through the elements of the tuple. The
#second for loop goes the the numbers in the ranges and populates
#(e_table) with my ascii characters.

def encoder():

# SECTION ONE
    a_ranges = (range(39,58), #ascii_ranges
                range(65,91),
                range(97,123))
    
    e_string = ''
    for i_range in a_ranges:
        for i_a_number in i_range: #i_ascii_number
            e_string = e_string + chr(i_a_number)
            

# ENCRYPT MESSAGE
#
# 1. Create empty string (e_msg) to accumulate the characters of the
#message.
#
# 2. The first for loop runs through each character in the message.
#
# 3. The if statement checks if each character is in the encryption
#string. If the character is not in the table, the character is not
#encrypted and is simply concatenated to the encrypted message. If the
#character is in the table, (a_number) grabs its position in the
#string, which is the equivalent of the ord() function. (e_a_number)
#then shifts the number by adding the value of the (key) like Zelle
#recommends. Here is where the "remainder %" operator comes in.
#
# 4. In "x = a % b", the "remainder %" operator makes sure that
#"x < b". For example, in "x = a % 5", "x <= 4" always, and never
#equal to or greater than five. In this problem, this property
#means that no key will ever push values beyond the legal ascii range
#(negatives or large numbers). For this reason, I use the "%"
#operater with the length of my encryption string.
#
# 5. (e_letter) converts the number back to a character in the
#context of my encryption table, which is the equivalent of the chr()
#function.
#
# 6. Finally, print the encrypted message.

    msg = input("Please enter message to be encoded/decoded: ")
    key = int(eval(input("Please enter key: ")))
    
    e_msg = '' #encrypted message
    
# SECTION TWO

    for letter in msg:
        
        if letter in e_string:
            
            a_number = e_string.find(letter) #ascii_number
            e_a_number = (a_number + key) % len(e_string) #encrypted_ascii_number
            e_letter = e_string[e_a_number] #encrypted_letter
            e_msg = e_msg + e_letter
            
        else:
            e_msg = e_msg + letter

# To affect all characters by this circular Caesar
#Cipher method. Comment out Sections 1,2 and uncomment Section 3.
#
# SECTION THREE
##    for letter in msg:
##        a_number = ord(letter)
##        #print(a_number, end=' ')
##        e_a_number = (a_number + key) %122 #122 encompasses all the
                #numbers, upper, and lowercase letters. For some
                #reason, it does not work well with other numbers.
##        e_letter = chr(e_a_number)
##        e_msg = e_msg + e_letter
    
            
    print(e_msg)


encoder()

Hey there,

A much easier way is to use the modulus of 26, for example: -3 % 26 = 23.
So your code will simply be:

def caesar_dec(message, key):
	ans = ''
	for i in message:
		ans += chr((((ord(i)-65)-key)%26) + 65)
	return ans

print caesar_dec(raw_input(),int(raw_input())

Later.
Daniel, South Africa

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.