Caesar Cipher Function in Python

175,885

Solution 1

I realize that this answer doesn't really answer your question, but I think it's helpful anyway. Here's an alternative way to implementing the caesar cipher with string methods:

def caesar(plaintext, shift):
    alphabet = string.ascii_lowercase
    shifted_alphabet = alphabet[shift:] + alphabet[:shift]
    table = string.maketrans(alphabet, shifted_alphabet)
    return plaintext.translate(table)

In fact, since string methods are implemented in C, we will see an increase in performance with this version. This is what I would consider the 'pythonic' way of doing this.

Solution 2

You need to move cipherText = "" before the start of the for loop. You're resetting it each time through the loop.

def caesar(plainText, shift): 
  cipherText = ""
  for ch in plainText:
    if ch.isalpha():
      stayInAlphabet = ord(ch) + shift 
      if stayInAlphabet > ord('z'):
        stayInAlphabet -= 26
      finalLetter = chr(stayInAlphabet)
      cipherText += finalLetter
  print "Your ciphertext is: ", cipherText
  return cipherText

Solution 3

This is an improved version of the code in the answer of @amillerrhodes that works with different alphabets, not just lowercase:

def caesar(text, step, alphabets):

    def shift(alphabet):
        return alphabet[step:] + alphabet[:step]

    shifted_alphabets = tuple(map(shift, alphabets))
    joined_aphabets = ''.join(alphabets)
    joined_shifted_alphabets = ''.join(shifted_alphabets)
    table = str.maketrans(joined_aphabets, joined_shifted_alphabets)
    return text.translate(table)

Example of usage:

>>> import string
>>> alphabets = (string.ascii_lowercase, string.ascii_uppercase, string.digits)
>>> caesar('Abc-xyZ.012:789?жñç', step=4, alphabets=alphabets)
'Efg-bcD.456:123?жñç'

References:
Docs on str.maketrans.
Docs on str.translate.
Docs on the string library

Solution 4

Using some ascii number tricks:

# See http://ascii.cl/
upper = {ascii:chr(ascii) for ascii in range(65,91)}
lower = {ascii:chr(ascii) for ascii in range(97,123)}
digit = {ascii:chr(ascii) for ascii in range(48,58)}


def ceasar(s, k):
    for c in s:
        o = ord(c)
        # Do not change symbols and digits
        if (o not in upper and o not in lower) or o in digit:
            yield o
        else:
            # If it's in the upper case and
            # that the rotation is within the uppercase
            if o in upper and o + k % 26 in upper:
                yield o + k % 26
            # If it's in the lower case and
            # that the rotation is within the lowercase
            elif o in lower and o + k % 26 in lower:
                yield o + k % 26
            # Otherwise move back 26 spaces after rotation.
            else: # alphabet.
                yield o + k % 26 -26

x = (''.join(map(chr, ceasar(s, k))))
print (x)

Solution 5

Batteries included

while 1:
    phrase = raw_input("Could you please give me a phrase to encrypt?\n")
    if phrase == "" : break
    print "Here it is your phrase, encrypted:"
    print phrase.encode("rot_13")
print "Have a nice afternoon!"

https://docs.python.org/2/library/codecs.html#python-specific-encodings

Python 3 update

The fine docs say

[Now the rot_13] codec provides a text transform: a str to str mapping. It is not supported by str.encode() (which only produces bytes output).

Or, in other words, you have to import encode from the codecs module and use it with the string to be encoded as its first argument

from codecs import decode
...
    print(encode(phrase, 'rot13'))
Share:
175,885
Admin
Author by

Admin

Updated on July 05, 2022

Comments

  • Admin
    Admin almost 2 years

    I'm trying to create a simple Caesar Cipher function in Python that shifts letters based on input from the user and creates a final, new string at the end. The only problem is that the final cipher text shows only the last shifted character, not an entire string with all the shifted characters.

    Here's my code:

    plainText = raw_input("What is your plaintext? ")
    shift = int(raw_input("What is your shift? "))
    
    def caesar(plainText, shift): 
    
        for ch in plainText:
            if ch.isalpha():
                stayInAlphabet = ord(ch) + shift 
                if stayInAlphabet > ord('z'):
                    stayInAlphabet -= 26
                finalLetter = chr(stayInAlphabet)
            cipherText = ""
            cipherText += finalLetter
    
        print "Your ciphertext is: ", cipherText
    
        return cipherText
    
    caesar(plainText, shift)
    
  • Fabio says Reinstate Monica
    Fabio says Reinstate Monica almost 8 years
    Are you sure you are answering the specific question asked by the OP? He wasn't asking for a way to rewrite the code, he just wanted some help at finding the bug.
  • cclauss
    cclauss over 7 years
    The solution above works in Python 2 but in Python 3 use str.maketrans() instead of string.maketrans().
  • Jed Fox
    Jed Fox about 7 years
    Please use the edit link to explain how this code works and don't just give the code, as an explanation is more likely to help future readers. See also How to Answer. source
  • Georgy
    Georgy over 5 years
    Improved version of this code for the case of several alphabets (lowercase, uppercase, digits, etc.): stackoverflow.com/a/54590077/7851470
  • Arnb
    Arnb over 4 years
    Here s is the encrypted string and k is the shift in integer.
  • Chris
    Chris about 4 years
    Code dumps without any explanation are rarely helpful. Stack Overflow is about learning, not providing snippets to blindly copy and paste. Please edit your question and explain how it works better than what the OP provided.
  • Amitai Irron
    Amitai Irron about 4 years
    You should also relate to the code provided by the asker of the question. It looks like their code is very close to working (even if being a bit un-elegant in places), so relating to it would strengthen learning.
  • Nick K9
    Nick K9 over 3 years
    This is a really nice approach which is configurable and avoids mod arithmetic. Very pythonic, thanks!
  • Nick K9
    Nick K9 over 3 years
    One downside, though, is that it doesn't allow character decrementing. To reverse the operation you would have to increment by the complement of the initial encryption.