2

I'm trying to make a "Caesar's Cipher" while using python..this is what I have so far. Could anyone tell me how this is looking? Am I going in the right direction? What am I missing? When I run the program to say for example (josh is cool) I don't get the cipher on the same line. It looks like this when I do main(3)

m
r
v
k
l
v
f
r
r
o

But it puts each letter on a new line. How could I do it so that it is on one line?

def main(k):

    if k<0 or k>231:
        print "complaint"
        raise SystemExit

    Input = raw_input("Please enter Plaintext to Cipher")

    for x in range(len(Input)):
        letter=Input[x]
        if letter.islower():
            x=ord(letter)
            x=x+k
            if x>122:
                x=x-122+97
            print chr(x),
        if letter.isupper():
            x=ord(letter)
            x=x+k
            if x>90:
                x=x-90+65
            print chr(x),
SilentGhost
  • 307,395
  • 66
  • 306
  • 293

8 Answers8

6

I like kaizer.se's answer, but I think I can simplify it using the string.maketrans function:

import string

first = raw_input("Please enter Plaintext to Cipher: ")
k = int(raw_input("Please enter the shift: "))

shifted_lowercase = ascii_lowercase[k:] + ascii_lowercase[:k]

translation_table = maketrans(ascii_lowercase, shifted_lowercase)

print first.translate(translation_table)
ctor
  • 5,938
  • 2
  • 26
  • 37
Neil Vass
  • 5,251
  • 2
  • 22
  • 25
2

This code should work pretty well. It also handles arbitrary offsets, including negative.

phrase = raw_input("Please enter plaintext to Cipher: ")
shift = int(raw_input("Please enter shift: "))

result = ''
for char in phrase:
    x = ord(char)

    if char.isalpha():
        x = x + shift

        offset = 65
        if char.islower():
            offset = 97

        while x < offset:
            x += 26

        while x > offset+25:
            x -= 26

        result += chr(x)

print result

The other way to do it, with a slightly different cipher, is simply rotate through all characters, upper and lower, or even all ascii > 0x20.

phrase = raw_input("Please enter plaintext to Cipher: ")
shift = int(raw_input("Please enter shift: "))

result = ''
for char in phrase:
    x = ord(char)

    x = x + shift

    while x < 32:
        x += 96

    while x > 127:
        x -= 96

    result += chr(x)

print result
Jeff B
  • 29,943
  • 7
  • 61
  • 90
1

Put a comma after each print statement; it will still put a space between the characters, but they'll all be on the same line. If you need to print them without the spaces, build them all into a single string and print that at the end.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • How would I build them into a single string? –  Oct 08 '09 at 17:17
  • @Josh: In Python, you can build a new string similar to using formatting characters in prints, e.g.: new_str = "String part: %s, Int part: %d" % (some_string, some_int) If you need to put it in a loop, first initialize the string to '' and then use += to add to it within the loop. – PTBNL Oct 08 '09 at 17:44
1

Here is a different method to show how we can handle this in a very clean way. We define an input alphabet and an output alphabet, then a translation table and use unicode.translate() to do the actual encryption.

import string
# Blatantly steal Lennart's UI design
first = unicode(raw_input("Please enter Plaintext to Cipher: "), "UTF-8")
k = int(raw_input("Please enter the shift: "))

in_alphabet = unicode(string.ascii_lowercase)
out_alphabet = in_alphabet[k:] + in_alphabet[:k]

translation_table = dict((ord(ic), oc) for ic, oc in zip(in_alphabet, out_alphabet))

print first.translate(translation_table)

It can be extended to uppercase letters as needed.

u0b34a0f6ae
  • 48,117
  • 14
  • 92
  • 101
0

Barring the syntax errors, your code seems to work.

However, I took the liberty of removing all duplicates, and cleaning it up:

first = raw_input("Please enter Plaintext to Cipher: ")
k = int(raw_input("Please enter the shift: "))

result = ''
for second in first:
    x=ord(second)
    x=x+k
    if x>90 and x<122:
        x=x-26
    elif x>122:
        x=x-26
    result += chr(x)

print first    
print result

Also "first" and "second" are really bad names for those variables. "Input" and "letter" is probably better.

Lennart Regebro
  • 167,292
  • 41
  • 224
  • 251
  • Okay, thank you. Just realized I posted the version with all of my syntax errors. I had one that was cleaned up, but thank you for the help –  Oct 08 '09 at 17:02
  • By the way, what are you meaning by "Please enter the shift:" –  Oct 08 '09 at 17:12
  • Your code does not handle punctuation. The original code ignored punctuation, as it is neither uppercase nor lowercase. In your example, you add k regardless. – Jeff B Oct 08 '09 at 17:16
  • @Josh: Ceasar Cipher does the cipher by shifting letters a certiain number. That's what I mean. – Lennart Regebro Oct 08 '09 at 20:41
  • @Jeff: Correctly, I don't handle punctuation, neither did Josh's original code. That's undefined in a typical ceasar cipher anyway. The original code does did differ between uppercase and lowercase, and did add k regardless. I do the same. – Lennart Regebro Oct 08 '09 at 20:44
  • Actually, the original code only adds k if letter.islower() or letter.issupper(), and punctuation is neither. Also, despite punctuation being undefined, it is probably best to either leave it alone or correctly shift it, otherwise you message could become undecipherable in the case that punctuation IS used. – Jeff B Oct 09 '09 at 02:22
  • Ah, I see what you mean. If you have plaintext punctuation, especially if that includes spaces, cracking it becomes so much easier. So in fact you shouldn't really leave it alone, you should raise an error if there is any. As an old cryptologist I just took that for granted. :-) – Lennart Regebro Oct 09 '09 at 05:39
0

I very simple, 3-shift solution without Umlauts and alike would be:

def caesar(inputstring):
    shifted=string.lowercase[3:]+string.lowercase[:3]
    return "".join(shifted[string.lowercase.index(letter)] for letter in inputstring)

and reverse:

def brutus(inputstring):
    shifted=string.lowercase[-3:]+string.lowercase[:-3]
    return "".join(shifted[string.lowercase.index(letter)] for letter in inputstring)

using it:

caesar("xerxes")
dorvak
  • 9,219
  • 4
  • 34
  • 43
0

For Python 3.3, try using the ord(), chr() and .isalpha functions:

m = input("What is your message?: ")
s = int(input("What is the shift?: "))
for i in m:
    if i.isalpha():
        if (ord(i)+s)>90:
            print(chr(ord(i)+s-26),end=""),
        elif chr(ord(i)+s-26)<65:
            print("The shift is invalid")
        else:
            print(chr(ord(i)+s),end=""),
    else:
        pass
0

Here is a oneliner.

>>> brutus=lambda message,cipher,direction:''.join([chr((ord(letter)+(cipher*direction))%256) for letter in message])
>>> encrypted= brutus('Message to be encrypted',14,1) #direction=1 for encryption
>>> encrypted
'[s\x81\x81ous.\x82}.ps.s|q\x80\x87~\x82sr'
>>> brutus(encrypted,14,-1) # direction=-1 for decryption
'Message to be encrypted'
>>>
thekindlyone
  • 509
  • 1
  • 6
  • 21