Shifting Values in Input String - python

I'm trying to do a Caesar Cipher and I've come pretty close. The problem is my output only prints out a single letter, not the whole line ciphered line. E is the most frequently used letter in English so the idea is to find the distance between E and the most frequently used letter in the input. And then shift everything over by that distance. I'm new at python, so I'm not very good yet. Thanks so much in advance! Here's the code I have so far:
maximum_character = unciphered_text[0]
maximum_count = unciphered_text.count(unciphered_text[0])
for char in unciphered_text:
if char is not " ":
if unciphered_text.count(char) > maximum_count:
maximum_character = char
print("The most frequent character used is: ", maximum_character)
ASCII_maximum = maximum_character.lower()
ASCII_number = ord(ASCII_maximum)
print(ASCII_number)
shift_distance = ord('e')-ASCII_number
print("The shift distance is: ", shift_distance)
def caesar_cipher(unciphered_text, shift_distance):
ciphered_text = ""
for char in unciphered_text:
cipher_process = ord(char)+shift_distance
post_translation = chr(cipher_process)
ciphered_text += post_translation
return ciphered_text
answer = caesar_cipher(unciphered_text, shift_distance)
print(answer)

You misindent return statement in caesar_cipher function.
Move your return statement out from loop:
def caesar_cipher(unciphered_text, shift_distance):
ciphered_text = ""
for char in unciphered_text:
cipher_process = ord(char)+shift_distance
post_translation = chr(cipher_process)
ciphered_text += post_translation
return ciphered_text

Related

Python Vigenere Cipher Encrypt method not encrypting properly

The encrypt method in my program is not encrypting correctly. I thought I figured out why using debug mode; it's because it reads the spaces between words as something it has to encrypt. So I tried typing a message without spaces but it still didn't come out correctly.
I figure the issue is the if statement with the key. I tried commenting lines out, changing statements, changing the if statement to a for loop, but it still isn't correct.
def main():
vig_square = create_vig_square()
message = input("Enter a multi-word message with punctuation: ")
input_key = input("Enter a single word key with no punctuation: ")
msg = message.lower()
key = input_key.lower()
coded_msg = encrypt(msg, key, vig_square)
print("The encoded message is: ",coded_msg)
print("The decoded message is: ", msg)
def encrypt(msg,key,vig_square):
coded_msg = ""
key_inc = 0
for i in range(len(msg)):
msg_char = msg[i]
if key_inc == len(key)-1:
key_inc = 0
key_char = key[key_inc]
if msg_char.isalpha() and key_char.isalpha():
row_index = get_row_index(key_char,vig_square)
col_index = get_col_index(msg_char,vig_square)
coded_msg = coded_msg+vig_square[row_index][col_index]
else:
coded_msg = coded_msg + " "
key_inc = key_inc+1
return coded_msg
def get_col_index(msg_char, vig_square):
column_index = ord(msg_char) - 97
return column_index
def get_row_index(key_char, vig_square):
row_index = ord(key_char) - 97
return row_index
def create_vig_square():
vig_square = list()
for row in range(26):
next_row = list()
chr_code = ord('a') + row
for col in range(26):
letter = chr(chr_code)
next_row.append(letter)
chr_code = chr_code + 1
if chr_code > 122:
chr_code = ord('a')
vig_square.append(next_row)
return vig_square
main()
This example was given to us:
Enter a multi-word message with punctuation: The eagle has landed.
Enter a single word key with no punctuation: LINKED
The encoded message is: epr oejwm ukw olvqoh.
The decoded message is: the eagle has landed.
But my encoded message comes out as:
epr iloyo sif plvqoh
You have two errors:
First, you don't use all characters in the key. Change the following line:
if key_inc == len(key)-1:
key_inc = 0
to
if key_inc == len(key):
key_inc = 0
Second, you move the key pointer even if you process a non-alpha character in the message (e.g. spaces). Do it only if you encode a character, i.e. make the following change:
if msg_char.isalpha() and key_char.isalpha():
...
key_inc = key_inc+1 # Move this line here
else:
...

Caesar Cipher with capital letters

So currently my Caesar cipher program runs well whenever I use lowercase letters. I want it however to work when I input a word or phrase with uppercase. This is the code I have now. Hopefully y'all can help me finish this.
user defined functions
def encrypt(message, distance):
"""Will take message and rotate it the distance, in order to create an encrypted message"""
encryption = ""
for ch in message:
ordvalue = ord(ch)
cipherValue = ordvalue + distance
if cipherValue > ord("z"):
cipherValue = ord("a") + distance - (ord("z") - ordvalue + 1)
encryption += chr(cipherValue)
return encryption
def decrypt(message, distance):
"""Will decrypt the above message"""
decryption = ""
for cc in message:
ordvalue = ord(cc)
decryptValue = ordvalue - distance
if decryptValue < ord("a"):
decryptValue = ord("z") - distance - (ord("a") - ordvalue - 1)
decryption += chr(decryptValue)
return decryption
def binaryConversion(message):
"""Will convert the word into binary code"""
binary = ""
for cb in message:
binaryString = " " #Binary number
binaryNumber = ord(cb)
while binaryNumber > 0:
binaryRemainder = binaryNumber % 2
binaryNumber = binaryNumber // 2
binaryString = str(binaryRemainder) + binaryString
binary += binaryString
return binary
while loop
run = True
while run:
#input
message = input("Enter word to be encrypted: ") #original message
distance = int(input("Enter the distance value: ")) #distance letters will be moved
#variables
fancy = encrypt(message, distance)
boring = decrypt(fancy, distance)
numbers = binaryConversion(message)
#output
print("\n")
print("Your word was: ", format(message, ">20s"))
print("The distance you rotated was: ", format(distance), "\n")
print("The encryption is: ", format(fancy, ">16s"))
print("The decryption is: ", format(boring, ">16s"))
print("The binary code is: ", format(numbers)) #I know an error comes here but it will work in the end
repeat = input("Would you like to encrypt again? Y/N ")
print("\n")
if repeat == "N" or repeat == "n":
run = False
else:
run = True
Finale
print("Thank you & as Julius Caesar once said, 'Veni, vidi, vici'")
Thank you
I would suggest you approach this problem in the mindset of a mapping rather than an offset. You can build the mapping based on the offset but character processing will be easier if you use a dictionary or some other form of one to one mapping.
For example:
offset = 5
source = "abcdefghijklmnopqrstuvwxyz"
target = source[offset:]+source[:offset]
source = source + source.upper()
target = target + target.upper()
encrypt = str.maketrans(source,target)
decrypt = str.maketrans(target,source)
e = "The quick brown Fox jumped over the lazy Dogs".translate(encrypt)
print(e)
d = e.translate(decrypt)
print(d)

Removing extra whitespace between words using for loop Python

I need to remove all excess white space and leave one space, between my words while only using if and while statements. and then state the amount of characters that have been removed and the new sentence
edit, it must also work for punctuation included within the sentence.
This is what I have come up with however it leaves me with only the first letter of the sentence i choose as both the number, and the final sentence. can anyone Help.
def cleanupstring(S):
lasti = ""
result = ""
for i in S:
if lasti == " " and i == " ":
i = ""
else:
lasti = i
result += i
return result
sentence = input("Enter a string: ")
outputList = cleanupstring(sentence)
print("A total of", outputList[1], "characters have been removed from your string.")
print("The new string is:", outputList[0])
Your code should be something like this:
def cleanupstring(S):
counter = 0
lasti = ""
result = ""
for i in S:
if lasti == " " and i == " ":
i = ""
counter += 1
else:
lasti = i
result += i
return result, counter
sentence = input("Enter a string: ")
outputList = cleanupstring(sentence)
print("A total of", outputList[1], "characters have been removed from your string.")
print("The new string is:", outputList[0])
The counter keeps track of how often you remove a character and your [0] and [1] work now the way you want them to.
This is because outputList is now a tuple, the first value at index 0 is now the result and the second value at index 1 is the counter.

Translator using a dictionary

I'm trying to solve a problem that can be found in the Book The Coder's Apprentice by Pieter Spronck, in section 13.2.4. This is the code I wrote so far:
english_dutch = {"last":"laatst", "week":"week", "the":"de", "royal":"koninklijk",
"festival":"feast", "hall":"hal", "saw":"zaag", "first":"eerst", "performance":"optreden",
"of":"van", "a":"een", "new":"nieuw", "symphony":"symphonie", "by":"bij",
"one":"een", "world":"wereld", "leading":"leidend", "modern":"modern",
"composer":"componist", "composers:componisten" "two":"twee", "shed":"schuur", "sheds":"schuren"}
text = "Last week The Royal Festival Hall saw the first \
performance of a new symphony by one of the world's leading \
modern composers, Arthur 'Two-Sheds' Jackson."
def clean(t):
t = t.lower()
t = t.split()
new_t = ""
for word in t:
new_word = ""
for letter in word:
if "a" <= letter <= "z":
new_word += letter
if letter == "-":
new_word += " "
else:
continue
new_t += new_word + " "
return new_t
def translate(t):
translation = ""
for word in t.split():
if english_dutch.get(word):
translation += english_dutch[word] + " "
else:
translation += word + " "
return translation
def auto_correct():
news = ""
a = translate(clean(text)).split()
for word in a:
if len(word) > 1:
news += word + " "
print(news)
auto_correct()
It seems to work OK, but when I run it, the words "composers" and "two" are not translated.
You forgot a comma between the word composers and the word two. In addiotion you wrote "composers:componisten" instead of "composers":"componisten". Change your dictionary like so
english_dutch = {"last":"laatst", "week":"week",
"the":"de", "royal":"koninklijk",
"festival":"feast", "hall":"hal",
"saw":"zaag", "first":"eerst",
"performance":"optreden",
"of":"van", "a":"een",
"new":"nieuw", "symphony":"symphonie",
"by":"bij",
"one":"een", "world":"wereld",
"leading":"leidend", "modern":"modern",
"composer":"componist",
"composers":"componisten", "two":"twee", # <- HERE
"shed":"schuur", "sheds":"schuren"}
Why it passed undetected? Check this:
>>> {"composers:componisten" "two":"twee"}
{'composers:componistentwo': 'twee'}
Because the comma was missing and the colon was within the string, python concatenated the strings, creating a useless (but valid) key/value pair.
This behaviour is documented here
Multiple adjacent string literals (delimited by whitespace), possibly using different quoting conventions, are allowed, and their meaning is the same as their concatenation. Thus, "hello" 'world' is equivalent to "helloworld".

Python Caesar and Vigenere Ciphers

For my programming class, I've been instructed to create two programs, each using the same two helper functions: alphabet_position(letter) and rotate_character(char, rot). One function uses the Caesar cipher to encrypt a message with a number of rotations, each given from the command line. The second program is meant to put more use to my Caesar program by turning it into the Vigenere Cipher. Both programs are meant to ignore (i.e., not rotate) special characters and I don't think numbers matter either. However, if the input letter is capitalized, the rotated output letter should be as well.
I've run into several issues with my code: My Caesar program only prints some capital letters. For example, with the arguments Hello, World! and 4, I receive an output of Lipps, svph! and I cannot figure out why that last capital letter isn't printing. When I attempt to pass in pYthon with 26 rotations, my program prints nothing.
My Vigenere program is also doing an odd thing with capital letters: with the passed arguments being Hello, World! and boom, I receive Iszxp, mr!.
Assignment is due in 48 hours and I'm kind of freaking out. 😬 Any and all help, criticism, etc. is welcome!
def alphabet_position(letter):
"""receives a letter and returns the 0-based numerical position of that letter within the alphabet."""
letter = letter.lower()
alphabet = "abcdefghijklmnopqrstuvwxyz"
numerical_pos = alphabet.find(letter)
return numerical_pos
def rotate_character(char, rot):
"""receives a character and an int 'rot', and rotates char by rot number of places to the right."""
alphabet = "abcdefghijklmnopqrstuvwxyz"
alpha_dict = dict(enumerate(alphabet))
new_char = ""
# ignore and return non-alphabetic characters
if char not in alphabet:
return char
# temporarily convert case to locate in alphabet
temp_char = char.lower()
if temp_char in alphabet:
# get original position of letter
orig_pos = alphabet_position(temp_char)
# take char, add rot to its index, mod 25 - 1
new_pos = (int(orig_pos) + int(rot))
if new_pos > 25:
new_pos = (new_pos % 25) - 1
elif new_pos < 0:
# avoid negative index error when rot is 26
new_char = char
# converting new_pos back to alpha
else:
new_char = alpha_dict[new_pos]
# if original char was upper/lower, return corresponding case for new_char
if char.islower():
new_char.lower()
else:
new_char.upper()
return new_char
from helpers import alphabet_position, rotate_character
# ------
# caesar cipher
# ------
def encrypt(text, rot):
new_text = ""
for char in text:
new_char = rotate_character(char, rot)
new_text += str(new_char)
return new_text
def main():
input_text = input("Enter a sentence to encrypt: ")
input_rot = int(input("Number of rotations: "))
print(encrypt(input_text, input_rot))
if __name__ == "__main__":
main()
from helpers import alphabet_position, rotate_character
# ------
# vigenere cipher
# ------
def encrypt(text, rot):
lower_alphabet = "abcdefghijklmnopqrstuvwxyz"
upper_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
keystream = 0
encrypted = ""
rot.lower()
for i in range(len(text)):
keychar = keystream % len(rot)
if text[i] in lower_alphabet:
new_char = rotate_character(text[i], alphabet_position(rot[keychar]))
new_char.lower()
encrypted += new_char
keystream += 1
elif text[i] in upper_alphabet:
new_char = rotate_character(text[i], alphabet_position(rot[keychar]))
new_char.upper()
encrypted += new_char
keystream += 1
else:
encrypted += text[i]
# stuck around here... vigenere isn't printing shifted capital letters and I
# can't figure out why.
return encrypted
def main():
input_text = input("Enter a sentence to encrypt: ")
input_rot = input("Enter your keyword: ")
print(encrypt(input_text, input_rot))
if __name__ == "__main__":
main()
Edit: helper functions edited to make code cleaner... Now it's only printing the one capital letter when I input pYthon with 4 rotations in Caesar. I'm lost.

Categories