1

Assignment:

Write a script that inputs a line of encrypted text and a distance value and outputs plaintext using a Caesar cipher.

My issue:

It's printing hello^3 world^2

I'm not entirely sure why. I would appreciate any and all assistance fixing or understanding the mistake in my code. (this is not assigned for a grade I.e. no due date doing for my own benefit)

The inputs it wants me to be able to use along with its respective:

Lipps${svph% 4

Jhss'tl'Pzothls5 7

Zu&hk2&ux&tuz&zu&hk 2

khoor#zruog$ 3

My code:

code = input("enter coded text: ") 
distance = int(input("enter value: ")) 
plainText = "" 
for ch in code: 
  ordvalue = ord(ch) 
  ciphervalue = ordvalue - distance 
  if ciphervalue < ord('a'): 
    ciphervalue = ord('z') - \
      (distance - (ord('a')-ordvalue - 1))
  plainText += chr(ciphervalue) 
print(plainText)
tonypdmtr
  • 3,037
  • 2
  • 17
  • 29
Navi Kzc
  • 19
  • 2
  • 8
  • code = input("enter coded text: ") distance = int(input("enter value: ")) plainText = "" for ch in code: ordvalue = ord(ch) ciphervalue = ordvalue - distance if ciphervalue < ord('a'): ciphervalue = ord('z') - \ (distance - (ord('a')-ordvalue - 1)) plainText += chr(ciphervalue) print(plainText) – Navi Kzc Jul 18 '19 at 21:59
  • 3
    Possible duplicate of [Caesar Cipher Function in Python](https://stackoverflow.com/questions/8886947/caesar-cipher-function-in-python) – norok2 Jul 18 '19 at 22:01
  • Please [edit] your question to include your code. You can use the link in my comment or the one under your question. In a comment it'll be all but impossible to debug your python code. – TemporalWolf Jul 18 '19 at 22:16
  • 2
    Also, I'll leave it to more expert people, but I think the `encryption` tag should be used for real encryption. Caesar cipher is so primitive that would not qualify for that. It reminds me of the old joke about the most used encryption method at IBM: EBCDIC :-) – norok2 Jul 18 '19 at 22:25

1 Answers1

2

First of all, you should decouple input/output from the processing, because your code will be easier to test:

def cipher(code, distance):
    plainText = ""
    for ch in code:
        ordvalue = ord(ch)
        ciphervalue = ordvalue - distance
        if ciphervalue < ord('a'):
            ciphervalue = ord('z') - (distance - (ord('a')-ordvalue - 1))
        plainText += chr(ciphervalue)
    return plainText

code = input("enter coded text: ")
distance = int(input("enter value: "))
print(cipher(code, distance))

Now, you have:

>>> cipher("Lipps${svph%", 4)
'\x8aello²world±'

I guess you expected something like 'Hello world!'. It's what you get if you remove the two lines:

if ciphervalue < ord('a'):
    ciphervalue = ord('z') - (distance - (ord('a')-ordvalue - 1))

Look:

def cipher2(code, distance):
    plainText = ""
    for ch in code:
        ordvalue = ord(ch)
        ciphervalue = ordvalue - distance
        plainText += chr(ciphervalue)
    return plainText

>>> cipher2("Lipps${svph%", 4)
'Hello world!'
>>> cipher2("Jhss'tl'Pzothls5", 7)
'Call me Ishmael.'
>>> cipher2("Zu&hk2&ux&tuz&zu&hk", 6) # was 2, but I guess it's 6
'To be, or not to be'
>>> cipher2("khoor#zruog$", 3)
'hello world!'

That was the fun part of the question. But I think you had a right intuition: what happens when the produced ordvalue value is not in an expected range (ie. negative or to big)?

>>> cipher2("hello", 103)
Traceback (most recent call last):
...
ValueError: chr() arg not in range(0x110000)

The function ord produces a unicode codepoint, between 0 and 1114111, but I think that for an exercice you can limit the range to 0 - 127 (ASCII chars):

def cipher3(code, distance):
    assert abs(distance) < 128
    plainText = ""
    for ch in code:
        ordvalue = ord(ch)
        ciphervalue = ordvalue - distance
        if ciphervalue < 0:
            ciphervalue += 128
        elif ciphervalue >= 128: # don't forget distance can be negative
            ciphervalue -= 128
        plainText += chr(ciphervalue)
    return plainText

>>> cipher3("hello", 103)
'\\x01~\\x05\\x05\\x08'
>>> cipher3('\x01~\x05\x05\x08', -103)
'hello'

Note that:

        if ciphervalue < 0:
            ciphervalue += 128
        elif ciphervalue >= 128: # don't forget distance can be negative
            ciphervalue -= 128

Is equivalent to:

        ciphervalue = ciphervalue % 128

If you want to have only printable characters, you can do use the string module:

import string
# string.printable is '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'

def cipher4(code, distance):
    assert abs(distance) < len(string.printable)
    plainText = ""
    for ch in code:
        ordvalue = string.printable.index(ch) # this is clearly suboptimal
        ciphervalue = (ordvalue - distance) % len(string.printable)
        plainText += string.printable[ciphervalue]
    return plainText

>>> cipher4("hello", 80)
'ByFFI'
>>> cipher4('ByFFI', -80)
'hello'
jferard
  • 7,835
  • 2
  • 22
  • 35