4
\$\begingroup\$

This program asks the user to input a List of words. It then returns a list of encrypted words, and a second list which specifies the numerical shifts used to encrypt those words. The idea was obtained from https://www.khanacademy.org/computing/computer-science/cryptography/crypt/v/one-time-pad

import random
def rotate_letter(letter, number):
 if letter == ' ':
 return letter
 if letter.islower():
 start = ord('a')
 elif not letter.islower():
 start = ord('A')
 normal_shift = ord(letter) - start
 new_letter = start + (normal_shift + number) % 26
 return chr(new_letter)
def avoid(letter):
 avoid = ' ,!?¿,*+-%/@1234567890'
 for i in avoid:
 if i == letter:
 return False
 return True
def rotate_word(word):
 new_word = ''
 random_series = []
 for letter in word:
 if avoid(letter):
 random_number = random.randint(1,26)
 new_letter = rotate_letter(letter, random_number)
 new_word += new_letter
 random_series.append(random_number)
 else:
 new_word += letter
 return (new_word, random_series)
def shift(words):
 index = 0
 encrypted_words = []
 random_shifts = []
 while index < len(words):
 (new_word, random_series) = rotate_word(words[index])
 encrypted_words.append(new_word)
 random_shifts.append(random_series)
 index += 1
 return (encrypted_words, random_shifts)
def get_input():
 words = []
 while True:
 user = (input('Input words to encrypt. Done when ready \n' ))
 if user == 'Done' or user == 'done':
 return words
 words.append(user)
def start():
 words = get_input()
 encrypted_words = []
 random_shifts = []
 (encrypted_words, random_shifts) = shift(words)
 print('UNENCRYPTED WORDS', words)
 print('ENCRYPTED WORDS', encrypted_words)
 print('RANDOM SHIFTS', random_shifts)
start()
200_success
146k22 gold badges190 silver badges479 bronze badges
asked Jan 6, 2017 at 20:50
\$\endgroup\$
2
  • \$\begingroup\$ Are you using Python 2 or Python 3? \$\endgroup\$ Commented Jan 6, 2017 at 21:00
  • \$\begingroup\$ @Peilonrayz I would guess Python 3 because of his usage of input. \$\endgroup\$ Commented Jan 6, 2017 at 22:10

1 Answer 1

2
\$\begingroup\$

Your function avoid is quite unnecessary and also confusing. I would expect avoid('@') to return True. When you store the letters as a global constant and as set, you should gain some speed (both because it does not have to be reconstructed again and again and because membership testing is very fast for a set. I replaced your function with letter not in letters_avoid.

Whenever you are doing string addition in Python, you are probably doing something wrong. This is because strings are immutable so for every addition a new string has to be created and the content of the strings to be added needs to be copied. This is quite slow. Rather, use a list to accumulate the letters of new_word and str.join them at the end.

When returning a tuple, the () are implicit. You can just write return a, b.

When iterating over words, you should just directly iterate over it, instead of its indices.

Using str.lower cuts down the double comparison if user == 'Done' or user == 'done' to if user.lower() == 'done':.

You should call your code with a if __name__ == '__main__': guard to allow importing your functions from another script without executing the whole script.

Final code:

import random
letters_avoid = set(' ,!?¿,*+-%/@1234567890')
def rotate_letter(letter, number):
 if letter == ' ':
 return letter
 if letter.islower():
 start = ord('a')
 elif not letter.islower():
 start = ord('A')
 normal_shift = ord(letter) - start
 new_letter = start + (normal_shift + number) % 26
 return chr(new_letter)
def rotate_word(word):
 new_word = []
 random_series = []
 for letter in word:
 if letter not in letters_avoid:
 random_number = random.randint(1, 26)
 new_word.append(rotate_letter(letter, random_number))
 random_series.append(random_number)
 else:
 new_word.append(letter)
 return "".join(new_word), random_series
def shift(words):
 encrypted_words = []
 random_shifts = []
 for word in words:
 new_word, random_series = rotate_word(word)
 encrypted_words.append(new_word)
 random_shifts.append(random_series)
 return encrypted_words, random_shifts
def get_input():
 words = []
 while True:
 user = input('Input words to encrypt. Done when ready \n')
 if user.lower() == 'done':
 return words
 words.append(user)
def start():
 words = get_input()
 encrypted_words, random_shifts = shift(words)
 print('UNENCRYPTED WORDS', words)
 print('ENCRYPTED WORDS', encrypted_words)
 print('RANDOM SHIFTS', random_shifts)
if __name__ == "__main__":
 start()
answered Jan 6, 2017 at 22:09
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.