Caesar Cipher in Python 3.4.3 - python

The output I should get if I type in "eat" should be "hdw" if I shift it by 3. However, the end result is only "w". I'm pretty sure I have everything I need, but maybe it's the formatting?
def shifter():
phrase = input("Please enter a message: ")
key = eval(input("Please enter the number of places to be shifted: "))
list = phrase.split()
for word in list:
for ch in word:
conversion = (chr)((ord(ch) - ord("a") + key) % 26 + ord("a"))
newPhrase = " "
newPhrase = newPhrase + conversion
print(newPhrase)
shifter()

The issue is that you are setting conversion inside your for loop, instead of appending to it, so only the last character in the word is appended to the newPhrase at the end.
You should be appending to conversion, rather than setting it.
Also, you should initialize newPhrase outside the loop and then append to it inside.
Example -
def shifter():
phrase = input("Please enter a message: ")
key = eval(input("Please enter the number of places to be shifted: "))
list = phrase.split()
newPhrase = ""
for word in list:
conversion = ''
for ch in word:
conversion += (chr)((ord(ch) - ord("a") + key) % 26 + ord("a"))
newPhrase = newPhrase + conversion + " "
print(newPhrase)
shifter()

I think it's with your indenting!
Right now, before you do anything with the variable conversion, you've already looped through every ch in word, so you're stuck at the last ch.
Try doing conversion += ... Instead of conversion = ...
(You might need to initialize conversion before that but idts.)

Related

Python Message Cipher Indexation Error + WhiteSpace issue

I am working on an exercise to encode a message in Python. The following function is supposed to take in a message and a number to shift the letters in each word by that amount in the alphabet i.e. the letter a if moved 3 spaced would become d.
I have two issues:
The length of the alphabet is only 26 characters long. If you shift a letter too far right i.e. past the 26th position of Z you get the following error:
IndexError: string index out of range
I'd be happy with a fix that shifts the index back to the start again and moves the letter index based on the remainder of whatever goes past 26 characters i.e. if there is a shift of 9 with the char y then the remaining 9 after 26 could be positioned start from a again, making y the letter i.
If I were to input a message with spaces i.e. "I need help", the returned characters do not retain the original white space between each word.
Can anyone help with questions 1 or 2?
def message_to_code():
normal_message = input(str("Please enter a message you would like coded: "))
Cipher_shift = int(input("Please enter the whole number you would like to act as the key to hide your message "))
Alphabet = "abcdefghijklmnopqrstuvwxyz"
Cipher_message = ' '
for letter in normal_message:
Encrypted_letter = Alphabet.find(letter) + Cipher_shift
Cipher_message = Cipher_message + Alphabet[Encrypted_letter]
return print(Cipher_message)
message_to_code()
Your first problem can be easily fixed by checking if Alphabet.find(letter) + Cipher_shift >= len(Alphabet). If it is, than Encrypted_letter = Encrypted_letter - len(Alphabet).
Your second problem was tricky to completely understand, but I think the fix you are looking for is checking if letter is a space. If it is, loop to the next character, if it's not, do the logic with that character.
The bug fixes look like this:
def message_to_code():
normal_message = input(str("Please enter a message you would like coded: "))
Cipher_shift = int(input("Please enter the whole number you would like to act as the key to hide your message "))
Alphabet = "abcdefghijklmnopqrstuvwxyz"
Cipher_message = ' '
for letter in normal_message:
if letter != ' ':
Encrypted_letter = Alphabet.find(letter) + Cipher_shift
if Encrypted_letter >= len(Alphabet):
Encrypted_letter -= len(Alphabet)
Cipher_message = Cipher_message + Alphabet[Encrypted_letter]
else:
Cipher_message += ' '
I also fixed some other problems. For example, if you have a capital letter, your original code wouldn't catch that, since Alphabet is only filled with lower-case letters. To fix this, I added a second array dedicated to capital-letters, and check to see if letter is capital or not.
The second fix is checking if letter is a part of the alphabet or not. If it isn't, that would mean letter is: '/', '.', ',', ':', ';', etc. If it does happen to be one of these characters, it just adds its original self to the encrypted string.
The modified code looks like this:
def message_to_code():
normal_message = input(str("Please enter a message you would like coded: "))
Cipher_shift = int(input("Please enter the whole number you would like to act as the key to hide your message "))
Alphabet = "abcdefghijklmnopqrstuvwxyz"
AlphabetCaps = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Cipher_message = ""
is_letter = True
for letter in normal_message:
if letter != ' ':
if Alphabet.find(letter) != -1:
Encrypted_letter = Alphabet.find(letter) + Cipher_shift
is_letter = True
elif AlphabetCaps.find(letter) != -1:
Encrypted_letter = AlphabetCaps.find(letter) + Cipher_shift
is_letter = True
else:
is_letter = False
if is_letter:
if Encrypted_letter >= len(Alphabet):
Encrypted_letter -= len(Alphabet)
if Alphabet.find(letter) != -1:
Cipher_message += Alphabet[Encrypted_letter]
else:
Cipher_message += AlphabetCaps[Encrypted_letter]
else:
Cipher_message += letter
else:
Cipher_message += ' '
return print(Cipher_message)

Outputs printed on same line - python

message = str(input())
for i in message:
if i == " ":
print(" ")
else:
# ord(i) returns the ASCII number for i
# To get the actual alphabetical position of i, you have to do ASCII of letter - ASCII of A + 1.
print(ord(i)-ord("a")+1)
This program converts each character of the users input to a letter, based on their alphabetical order (a = 1, b = 2, ect) and prints each number output on a new line. How do I get change this so that when each number is printed, it is on the same line as the last? (eg 123)
Set the optional end argument to "" in print() as:
print(ord(i)-ord("a")+1, end="")
Use this
print("what ever you want to print",end= " ")
It will print without taking the cursor down a line.

How can I convert the output of a for loop into a string?

I'm tasked with creating a "Caesar Cipher" that takes two inputs (a string for the message, and an integer for the shift) and returns a string that's just the input string with all of its characters shifted by the amount specified in the shift argument for each character in the string (including punctuation marks, special characters and capital letters).
I've made this... and it works, but the output displays like the output of a for loop when I need it to be a string. How can I convert it back into a string on a single line?
message = input("What is your message?")
shift = input("What is your shift?")
shift = int(shift)
for i in message:
result = ((ord(i))+shift)
print(chr(result))
TERMINAL
What is your message?hello
What is your shift?3
k
h
o
o
r
message = input("What is your message?")
shift = input("What is your shift?")
shift = int(shift)
final_message = ''
for i in message:
result = ((ord(i))+shift)
char = chr(result)
final_message += char
print(char)
print(final_message)
You can use (generator) comprehension to simplify the loop, and use join to make a string:
message = input("What is your message? ")
shift = int(input("What is your shift? "))
result = ''.join(chr(ord(c) + shift) for c in message)
print(result)
Example:
What is your message? hello
What is your shift? 3
khoor
If you do want to use for, you can do instead:
result = []
for c in message:
result.append(chr(ord(c) + shift))
result = ''.join(result)
That is, store the intermediate values in a list, and then combine them once the loop is finished.

Substituting the instance of a character, except the first, in a input string

Since strings in python are immutable, i tried this workaround: I first broke the string in its character components, putting them inside a list. Then i proceeded by looping inside this list and substituting the second occurrence of the character i wanted to modify into the target character.
The last part was of course to re-build the string from the new list thus obtained.
def modify():
space = " "
# This is the input part
varstr = input("Insert a string to modify:\n> ")
if space in varstr:
print("Please insert a string without space")
modify()
varchar = input("Insert a SINGLE character to modify in $:\n> ")
if len(varstr) > 1:
print("Please insert a single character, without spaces")
counter = 0
liststr = []
stringout = ""
#Creating the list composed by the characters of the string
for i in varstr:
liststr.append(i)
#Looping through the string and substituting the character from its second occurence
for j in range(len(liststr)):
if counter >= 1 and liststr[j] == varchar:
liststr[j] = "$"
elif counter == 0 and liststr[j] == varchar:
counter += 1
for k in liststr:
stringout += k
return stringout
My question is: can this code be made a bit more tidy?
Edit: The Sample Input may be "Google" and the character "o". The sample output would be then
Go$gle
You could do the following:
char = "a"
stri = "santaclaus"
char.join("$".join(s.split(char)) for s in stri.split(char, 1))
# 'sant$cl$us'
This splits on the first char occurrence, and joins the tokens back together after "char.splitting and '$'.joining" them.
def modify():
while True:
varstr = input("Insert a string to modify:\n> ")
if ' ' in varstr:
print("Please insert a string without space")
else:
break
while True:
varchar = input("Insert a SINGLE character to modify in $:\n> ")
if len(varchar) > 1:
print("Please insert a single character, without spaces")
else:
break
return varstr[0] + varstr[1:].replace(varchar, '$')
Try this:
def modify():
while True:
varstr = input("Insert a string to modify:\n> ")
if len(varstr) > 0 and ' ' not in varstr:
break
print("Please insert a string without space")
while True:
varchar = input("Insert a SINGLE character to modify in $:\n> ")
if len(varchar) == 1 and varchar != ' ':
break
print("Please insert a single character, without spaces")
first = varstr.find(varchar) + 1
varstr = varstr[:first] + varstr[first:].replace(varchar, "$")
return varstr
A few points about the question code:
You can use a while loop as shown, instead of recursion, to repeat the input. If you really want to use recursion you have to add a return after the modify() call.
If you want to convert a string to list of characters, you can use strlist = list(varstr). Then you can mutate, and return to string using ''.join(strlist)

How to assign item to a string in python

I'm really new to programming in general, but I'm a fast learner. I've been working on a project. I wanted to make a simple hangman game, but I hit a road block and I'd like to figure it out before continuing.
I'm trying to assign correct guesses to an empty variable and print is as they go, but it seems I can't assign "items" to strings. Is there an alternative method I could use?
Here's the code
switch = True
def hangman():
guess_number = 0 # Var that keeps track of the guesses
secret_word = input("What is the secret word?\n>") # Gets the secret word
print("The secret word is %d characters long." % len(secret_word)) # Lenght of secretword
answer = "-" * len(secret_word) # Create empty answer for assigning characters
while switch is True:
guess_number = guess_number + 1 # Counts the guesses
index_num = 0 # Tring to use this to assign correct guesses to answer
user_guess = input("Guess #%d >" % guess_number) # Gets user guess
print("Secret word: " + answer) # prints empty answer as "----"
for each_char in secret_word:
index_num = index_num + 1 # Counting index for assigning to answer variable
print("testing index #" + str(index_num))
if user_guess is each_char:
print("Correct Guess for index #" + str(index_num))
#------> answer[index_num] = each_char <--------
hangman()
Python strings are immutable, they can't be modified.
You can treat your string as a list
answer = list("-" * len(secret_word))
Then join chars together
answer_str="".join(answer)
There are some other ways, that have been suggested. If you're determined to keep the string answer, try this:
answer = answer[:index_num] + each_char + answer[index_num+1:]
This creates a new string by adding (string add is concatenation) together three substrings: first, the substring created by slicing the original string from zero (default: [:) up to index_num, non-inclusive. That is, answer[0] ... answer[index_num-1]. Then the each_char, which is a string (or a char, same difference). Finally, another substring, this one from index_num+1 running up to the end (default: :]).

Categories

Resources