1

So i tried to shift a single letter down the index scale such as 'a' becoming 'd' when you shift it '3', but now i want to do a whole word so every letter get shifted down at the same time, here is what i have so far:

Alphabet=['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']
W=input("Enter Word: ")
S=int(input("Please choose a number between -51 and 51: "))
I=(Alphabet.index(W))
J=I+S
if J>25:
print("Please choose a number that is between -51 and 51")
else:
print("Your code word is: ",Alphabet[J])

The output was:

Enter Word: today
Please choose a number between -51 and 51: 3
Traceback (most recent call last):
File"C:/Users/Owner/OneDrive/Documents/Python/Word Shift.py", line 4, in <module>
I=(Alphabet.index(W))
ValueError: 'today; is not in list

FYI, I am literally a beginner in python so i don't know a lot of "Stuff", If it isn't too much trouble can you please tell me where i went wrong and what each part of your coded solution does?

PeterE
  • 5,715
  • 5
  • 29
  • 51
ter0revil
  • 9
  • 1
  • 1
    26 is between -51 and 51 and you would need to index each letter not the whole word – Padraic Cunningham Jan 08 '15 at 11:28
  • Its because you try to find the index of "today" in the list Alphabet (You may want to change that to lowercase). But the list Alphabet does not have it which will raise a value-error. – Vincent Beltman Jan 08 '15 at 11:29
  • Isn't it so obvious? You tried to get an index of "today" in the list Alphabet which of course don't contain the word "today" inside. – dragon2fly Jan 08 '15 at 11:31
  • possible duplicate of [Caesar Cipher Function in Python](http://stackoverflow.com/questions/8886947/caesar-cipher-function-in-python) – markcial Jan 08 '15 at 11:35

5 Answers5

1

some_list.index(element) raises a ValueError if element is not in some_list. Alphabet.index(W) will throw this error unless the inputted word is one character, because Alphabet is just a list of single characters.

You need to create an empty list, loop over the characters in W, convert each character using Alphabet.index and append to the list. After the loop, you use the ''.join(some_list) idiom to join the whole list into one string.

new_word_list = []
for char in W:
    I = Alphabet.index(char)
    new_word_list.append(Alphabet[I+S])
new_word = ''.join(new_word_list)

Your code also won't work because your Alphabet list is only 26 elements long, but the user is allowed to enter a number that will take the index above 26. For example, if someone chose the number 1 and 'z' was one of the characters, your code will throw an index error because Alphabet.index('z') is 26, and there is no such thing as the 27th index.

The easiest solution to this (though not efficient) is to do this when you're defining Alphabet:

Alphabet=['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']*3

This means your Alphabet list is going to be 78 elements long.

Once you're more comfortable with Python, you might want to look at built-in functions such as chr, ord, and the contents of the strings module, which will simplify some of the things you are trying to do.

zehnpaard
  • 6,003
  • 2
  • 25
  • 40
1
import string

alphabet= string.ascii_lowercase # this is a string containing all lower-case characters

valid_range= len(alphabet)-1 # calculate how far it's possible to shift characters

word= input("Enter Word: ") # get a word to encode from the user

while True: # get a valid shift from the user
    try:
        shift= int(input("Please choose a number between -{0} and {0}: ".format(valid_range)))
    except ValueError:
        print('You must enter a number')
        continue
    if -valid_range <= shift <= valid_range:
        break
    print('The number must be between -{0} and {0}'.format(valid_range))

def shift_chars(text, shift, alphabet):
    # create a translation table: from_char -> to_char
    # using the original and the shifted alphabet
    trans_table= str.maketrans(alphabet, alphabet[shift:]+alphabet[:shift])
    # then use it to shift all characters
    return text.translate(trans_table)

code_word= shift_chars(word, shift, alphabet)
print("Your code word is:", code_word)

Example:

Enter Word: abc
Please choose a number between -25 and 25: 1
Your code word is: bcd
Aran-Fey
  • 39,665
  • 11
  • 104
  • 149
  • Props for using the `string` functions `lowercase`, `maketrans` and `translate`, very pythonic. Remark: with python 3 those functions have moved to `string.ascii_letters`, `str.maketrans` and `str.translate`. Potential Improvement: handle uppercase characters by adding them to the alphabet and then halving the valid_range. (`string.ascii_letters` already includes both cases). – PeterE Jan 08 '15 at 12:19
  • I is not declared as such. I just thought it should be mentioned for the sake of completes. But the OP uses print as a function, not as a statement. – PeterE Jan 08 '15 at 12:47
  • @PeterE: The `input("Enter Word: ")` gives it away, actually. – Aran-Fey Jan 08 '15 at 13:03
0

Your error mean the word today is not on your Alphabet list. I would use numpy to do accomplish your target in a simple way.

import numpy as np

Alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u',
            'v', 'w', 'x', 'y', 'z']

mask = np.array(Alphabet)    # make a numpy array of string of anything in Alphabet

W = raw_input("Enter a lowercase Word: ")
S = int(raw_input("Please choose a number between -51 and 51: "))

mask=np.roll(mask, S)   # shift the array to left or right `abs(S)` time
dictionary = {x:y for x,y in zip(Alphabet, mask)}   # make a dictionary to look up after
new_word =''.join([dictionary[char] for char in W])   # make new word after looked up
print new_word

And this is a test case:

Enter Word: hello
Please choose a number between -51 and 51: -3
khoor

In fact, the number is not limited within the [-51, 51] range. You can try any number you one. The time that word's mask rotated is equal to the inputted number. If the number is positive, the mask is rotated to the right and vice versa.

dragon2fly
  • 2,309
  • 19
  • 23
0

As @zehnpaard pointed out, your problem is that you are trying to find the whole word in the alphabet, and what you need to do is find all the individuals letters. You can do that using list comphrehension:

indexes = [Alphabet.index(c) for c in word]

This will give you:

>>> [Alphabet.index(c) for c in "hello"]
[7, 4, 11, 11, 14]

Now, what you want to do is add a number, but you want to make your array cyclical, this is achieved using the mod (%) operator, assuming len(Alphabet) = 26, shift = 15 and letter t (index 19):

>>> (19 + 15) % 26
8

There you have your circular array, without needing to triplicate. This is generalized with another list comprehension in the following form:

>>> n = len(Alphabet)
>>> shift = ### whatever you get in the input
>>> new_indexes = [(i+shift)%n for i in indexes]

You get the new chars by looking into the alphabet:

>>> new_chars = [Alphabet[i] for i in new_indexes]

And you get back your word by joining the chars:

>>> cipher_word = ''.join(new_chars)

All this process can be done in less lines... this way is more clear. Just to sumarize:

>>> word = "stackoverflow"
>>> shift = 10
>>> n = len(Alphabet)
>>> indexes = [Alphabet.index(c) for c in word]
>>> new_indexes = [(i+shift)%n for i in indexes]
>>> new_chars = [Alphabet[i] for i in new_indexes]
>>> cipher_word = ''.join(new_chars)
>>> print cipher_word
cdkmuyfobpvyg
Imanol Luengo
  • 15,366
  • 2
  • 49
  • 67
0
import string

alphabet = list(string.ascii_lowercase)

user_input = raw_input("Enter the code : ").lower()

number = int(raw_input("Enter Number between -26 and 26 : "))

code = ""

for i in range(len(user_input)):

        alphabet[alphabet.index(user_input[i]) + number]
        code = code + string.replace(user_input, user_input[i], alphabet[alphabet.index(user_input[i]) + number])[i]

print "User code is : %s " % code

---Output

Enter the code : code

Enter Number between -26 and 26 : 5

User code is : htij

PeterE
  • 5,715
  • 5
  • 29
  • 51
hariK
  • 2,722
  • 13
  • 18
  • I think you can dispense with converting the alphabet into a list. A string is also indexable. – PeterE Jan 08 '15 at 12:44