Python Forum
Wrap from end to beginning. 27 to 1, 28 to 2 etc - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: Wrap from end to beginning. 27 to 1, 28 to 2 etc (/thread-11126.html)



Wrap from end to beginning. 27 to 1, 28 to 2 etc - DreamingInsanity - Jun-23-2018

As a simple project I wanted to make a Caeser cipher encoder and decoder using my own knowledge. I got the encoding done but am stuck on the wrap around if you go above 26. At the title said 27 goes back to 1 or -1 goes back to 26. I have tried lots but cant get it to work. It works when you input a shift of about 0 - 4 or have no characters in it like a 'z'. But otherwise, I get a 'KeyErrror' ranging from about 27 - 30.

Here is my code. Please note: this may be just generally bad code / bad way of doing the conversion, but I would appreciate it if you did not improve it since I wanted to use as much of my own knowledge as possible and not have to use forums. Also there may be variable in there that don't do anything, they were just used for previous testing or conversion methods.

from __future__ import print_function
import time
import string
import operator

num = 0
convto = {"a" : 1, "b" : 2, "c" : 3, "d" : 4, "e" : 5, "f" : 6, "g" : 7, "h" : 8, "i" : 9, "j" : 10, "k" : 11, "l" : 12, "m" : 13 , "n": 14, "o" : 15, "p": 16, "q" : 17, "r" : 18, "s" : 19, "t" : 20, "u" : 21, "v" : 22, "w" : 23, "x" : 24, "y" : 25, "z" : 26} #a = 0, b = 1 ect.
convfrom = {"1" : "a", "2" : "b", "3" : "c", "4" : "d", "5" : "e", "6" : "f", "7" : "g", "8" : "h", "9" : "i", "10" : "j", "11" : "k", "12" : "l", "13" : "m" , "14" : "n", "15" : "o", "16" : "p", "17" : "q", "18" : "r", "19" : "s", "20" : "t", "21" : "u", "22" : "v", "23" : "w", "24" : "x", "25" : "y", "26" : "z"}
usercipher = []
caeserints = []


def main():
    global cipher
    global shift
    print("This will decrypt/encrypt Caeser Ciphers automatically!")
    time.sleep(0.5)
    print("----------------------------------------------------")
    time.sleep(1)

    cipher = input("Input cipher: ")
    cipher = cipher.replace(" ", "")
    cipher = cipher.lower()
    shift = int(input("Input the shift: "))
    encrypt()


def encrypt():
    global encrypt
    global num
    usercipher = list(cipher)

    for letter in usercipher:
        numlist = convto[letter] + shift
        numlist = str(numlist)
        caeserints.append(numlist)
    for i in range(0,len(caeserints)):
        if oversize >= str(27):
            num = 0

        num += 1
        charsout = convfrom[caeserints[num]]
        #print(charsout)   

if __name__ == '__main__':
    main()
Thanks in advance,
Dream.


RE: Wrap from end to beginning. 27 to 1, 28 to 2 etc - j.crater - Jun-23-2018

Modulo operator (%) is what you are looking for to solve for shifting over 26. It returns the remainder of integer division.

>>> 26 % 26
0
>>> 27 % 26
1
>>> 28 % 26
2
>>> 3 % 26
3



RE: Wrap from end to beginning. 27 to 1, 28 to 2 etc - DreamingInsanity - Jun-23-2018

Thanks for the reply! I will try it out as soon as possible.
Dream.


RE: Wrap from end to beginning. 27 to 1, 28 to 2 etc - DreamingInsanity - Jun-24-2018

It works perfectly for postive numbers but for any negative number (-5 % 1) gives me 0. Is there another option for negative numbers?
Thanks,
Dream.

I have tried this code:
over_limit = num
        if int(over_limit) > max_limit:
            left_over = over_limit % 26
            caeserint.append(left_over)
But I am still getting a KeyError.
Any help?


RE: Wrap from end to beginning. 27 to 1, 28 to 2 etc - DreamingInsanity - Jun-24-2018

YAY! I got it to work:
if int(caeserints[num]) > max_limit:
            left_over = over_limit % 26
            caeserints[num] = str(left_over)



RE: Wrap from end to beginning. 27 to 1, 28 to 2 etc - ljmetzger - Jun-24-2018

Good job. Take a look at the following code, and write finish the decryption algorithm:

NOTES and suggestions:
a. Make variables local if possible - i.e. avoid globals
b. Pass items to functions as parameters
c. Make variable names more meaningful
d. I hard coded the inputs for easier debugging
e. The key to success is to be able to identify 'test cases' when debugging (e.g. adding punctuation, positive and negative shifts [large and small], test string with all letters of the alphabet [caps and lower case])
from __future__ import print_function
import time
import string
import operator
 
num = 0
convto = {"a" : 1, "b" : 2, "c" : 3, "d" : 4, "e" : 5, "f" : 6, "g" : 7, "h" : 8, "i" : 9, "j" : 10, "k" : 11, "l" : 12, "m" : 13 , "n": 14, "o" : 15, "p": 16, "q" : 17, "r" : 18, "s" : 19, "t" : 20, "u" : 21, "v" : 22, "w" : 23, "x" : 24, "y" : 25, "z" : 26} #a = 0, b = 1 ect.
convfromlist = {"1" : "a", "2" : "b", "3" : "c", "4" : "d", "5" : "e", "6" : "f", "7" : "g", "8" : "h", "9" : "i", "10" : "j", "11" : "k", "12" : "l", "13" : "m" , "14" : "n", "15" : "o", "16" : "p", "17" : "q", "18" : "r", "19" : "s", "20" : "t", "21" : "u", "22" : "v", "23" : "w", "24" : "x", "25" : "y", "26" : "z"}
 
def remove_punctuation_and_numbers(s):
    _s = ""
    for _c in s:
        if  _c.isalpha():
            _s = _s + _c     
    return _s
 
def main():
    print("This will decrypt/encrypt Caeser Ciphers automatically!")
    time.sleep(0.5)
    print("----------------------------------------------------")
    time.sleep(1)
 
    # cipher = input("Input cipher: ")
    cipher = "Hello World, am I a Zebra?"
    # cipher = "abCDEFghijklmnopqrstuvwxyz+-)(1234567890"
    cipher = remove_punctuation_and_numbers(cipher)
    cipher = cipher.lower()
    print("After remove punctuation cipher is '{}'".format(cipher))
    # shift = int(input("Input the shift: "))
    shift = -1
    encrypted_string = encrypt(cipher, shift)
    print("The encrypted string is            '{}'".format(encrypted_string))
 
    decrypted_string = decrypt(encrypted_string, shift)
    print("The decrypted string is            '{}'".format(decrypted_string))

    
def encrypt(cipher, shift):
    caeserints = []
    for letter in cipher:
        # print(letter)
        numlist = (convto[letter] + shift)  % 26
        if numlist == 0:
            numlist = 26
        numlist = str(numlist)
        caeserints.append(numlist)
    # print(caeserints)    
    # print(len(caeserints))    
    
    encrypted_string = ""
    for num in caeserints:
        # print(num, type(num))
        charout = convfromlist[num]
        # print(num, charout)
        encrypted_string += charout
    return encrypted_string
    

def decrypt(encrypted_string, shift):
    decrypted_string = ""

    # To be completed

    return decrypted_string
    
if __name__ == '__main__':
    main()
Lewis