Shifting within a list when past end range?

90 views Asked by At

I created a simple program for performing a Caeser cipher on a user inputted string.

In order to allow the shift to go past the end of the list and back to the beginning, I simply duplicated all the list values for that list.

Is there a more pythonic way of achieving this result so that it will shift back to the beginning and continue to shift if the shift goes past the end of the list range?

while True:
    x = input("Enter the message you would like to encrypt via a Caeser shift; or type 'exit': ")
    if x == 'exit': break
    y = int(input("Enter the number by which you would like to have the message Caeser shifted: "))
    alphabet = list('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz')
    encoded = ''
    for c in x:
        if c.lower() in alphabet:
            encoded += alphabet[alphabet.index(c)+y] if c.islower() else alphabet[alphabet.index(c.lower())+y].upper()
        else:
            encoded += c
    print(encoded)
3

There are 3 answers

1
xnx On BEST ANSWER

If you do want to do it this way, then you're best bet is to use modular arithmetic to calculate the index in alphabet:

while True:
    x = input("Enter the message you would like to encrypt via a Caeser shift; or type 'exit': ")
    if x == 'exit': break
    y = int(input("Enter the number by which you would like to have the message Caeser shifted: "))
    alphabet = 'abcdefghijklmnopqrstuvwxyz'
    encoded = ''
    for c in x:
        if c.lower() in alphabet:
            i = (alphabet.index(c.lower()) + y) % 26
            encoded += alphabet[i] if c.islower() else alphabet[i].upper()
        else:
            encoded += c
    print(encoded)

Some notes: you don't need to convert your alphabet to a list: strings are iterable too; a dictionary might be a better alternative data structure.

1
Mehdi On
x = "message"
y = 10 # Caeser shift key
alphabet = list('abcdefghijklmnopqrstuvwxyz')
encoder = dict(zip(alphabet, alphabet[y:]+alphabet[:y])) 
encoded = "".join(encoder[c] for c in x)
4
Aditya On

Here's the best pythonic way I could write. You don't even need a list because each character has an ASCII value which has a predefined range. Just play around with it.

def encrypt(text,key):
    return "".join( [  chr((ord(i) - 97 + key) % 26 + 97)  if (ord(i) <= 123 and ord(i) >= 97) else i for i in text] )

ord(i) gives you the ascii value. 97 is value of 'a'. So ord(i) - 97 is same as searching for index of i in your list. Add the key to it to shift. chr is opposite of ord and it converts ascii value back to the character.

So just one line of code within the method.