I am in an into to Programming class and the assignment is in part to shift the letters of a valid password by +1 if it is a letter or number and -1 if it is a !##$ special character. I have most of it working with my below code but I always get the wrong output for the special characters. If I use to the code of anything high like 128 then I get the wrong symbol.
I am using the code from an encryption program from the other week and slowly changing things but I feel like this is too involved for something simple
If I enter the password UMA#augusta2020 I need to get the output VNB?bvhvtub3131 but I either end up with a space, b, or wrong symbol when I change the code input between 26,64,96,128, etc.
I have updated the code to fix small errors
def main():
print("This program validates and encrypts a password")
print()
main()
# The Encryption Function
def cipher_encrypt(plain_text):
encrypted = ""
for c in plain_text:
if c.isupper(): #check if it's an uppercase character
c_index = ord(c) - ord('A')
# shift the current character by key positions
c_shifted = (c_index + 1) % 26 + ord('A')
c_new = chr(c_shifted)
encrypted += c_new
elif c.islower(): #check if its a lowecase character
c_index = ord(c) - ord('a')
c_shifted = (c_index + 1) % 26 + ord('a')
c_new = chr(c_shifted)
encrypted += c_new
elif c.isdigit():
# if it's a number,shift its value
c_new = (int(c) + 1) % 10
encrypted += str(c_new)
else:
# if its neither alphabetical nor a number, -1
c_shifted = (c_index - 1) % 128 + ord('a')
c_new = chr(c_shifted)
encrypted += c_new
return encrypted
plain_text =input("Enter your Password: ")
print()
ciphertext = cipher_encrypt(plain_text)
print()
print("Your Password: ", plain_text)
print()
print("Your password is valid and encrypted it is: ", ciphertext)
print()
Here is a much cleaner approach:
def cipher_encrypt(plain_text):
alpha = 'abcdefghijklmnopqrstuvwxyz'
digits = '0123456789'
puncs = '!"#$%&\'()*+,-./:;<=>?#[\\]^_`{|}~'
encrypted_text = ''
for c in plain_text:
if c.lower() in alpha:
c_index = alpha.index(c.lower())
e_index = (c_index + 1)%len(alpha)
if c == c.lower():
encrypted_text += alpha[e_index]
else:
encrypted_text += alpha[e_index].upper()
elif c in digits:
c_index = digits.index(c)
e_index = (c_index + 1)%len(digits)
encrypted_text += digits[e_index]
else:
c_index = puncs.index(c)
e_index = (c_index +len(puncs) - 1)%len(puncs)
encrypted_text += puncs[e_index]
return encrypted_text
In this approach I deal with each caharcter in plain text by:
Determining idf the char is part of alpha by making use of the c.lower() function to isolate alpha chars and then find an index modulo the len of alpha. Then I determine if I need an uppercase char or lower case in the encrypted text.
I use the same modulo approach for digits, but don't have to worry about upper and lower, finally
I find the index for the punctuations found in the plain_text
Related
I've tried using "if" statements to skip characters that aren't alphabetical but It keeps ignoring the code and adding the shifted characters. I'm trying to shift the user input by 2 but the encoded-word should not have any special characters so the shift would wrap round back from z-a.
The code below is before I tried "if" statements.
encoded_word = ("")
decoded_word = ("")
def Encoding(text):
global encoded_word
letter_list = list(text)
length_list = len(text)
for i in range (0,length_list):
letter_ord = ord(letter_list[i])
encoded_letter = chr(letter_ord+2)
encoded_word = (encoded_word + encoded_letter)
print ("The encoded word is now:",encoded_word)
def Decoding(text):
global decoded_word
letter_list = list(text)
length_list = len(text)
for i in range (0,length_list):
letter_ord = ord(letter_list[i])
decoded_letter = chr(letter_ord-2)
decoded_word = (decoded_word + decoded_letter)
print ("The decoded word is:",decoded_word)
decode_encode = str(input("Would you like to encode or decode text? encode/decode: "))
if decode_encode == "encode":
user_word = str(input("Enter in a word to encode: "))
Encoding(user_word)
if decode_encode == "decode":
user_word = str(input("Enter in the encoded word: "))
Decoding(user_word)
to check if a character is a letter you can use isalpha().
For example should print just d and f:
list = ["3","2","-","1","4","5","-","3","d", "f"]
character_list = []
for i in list:
if i.isalpha():
character_list.append(i)
print (character_list)
I think you are on the right track you just to deal with a couple more edge cases such as if the shift amount is greater than 26, or if the shift needs to wrap around, etc. Additionally, string concatenation using + is inefficient since a copy of the existing string needs to be made each concatenation. Therefore, consider appending to a list of characters instead and only creating an output encoded/decoded string at the end:
SHIFT_AMOUNT = 2
def encode(text):
res = []
actual_shift_amount = SHIFT_AMOUNT % 26
for ch in text:
new_letter = ch
if ord('a') <= ord(ch) <= ord('z'):
if (ord(ch) + actual_shift_amount) <= ord('z'):
new_letter = chr(ord(ch) + actual_shift_amount)
else:
new_letter = chr(ord('a') + actual_shift_amount - (ord('z') - ord(ch) + 1))
elif ord('A') <= ord(ch) <= ord('Z'):
if (ord(ch) + actual_shift_amount) <= ord('Z'):
new_letter = chr(ord(ch) + actual_shift_amount)
else:
new_letter = chr(ord('A') + actual_shift_amount - (ord('Z') - ord(ch) + 1))
res.append(new_letter)
return ''.join(res)
def decode(text):
res = []
actual_shift_amount = SHIFT_AMOUNT % 26
for ch in text:
new_letter = ch
if ord('a') <= ord(ch) <= ord('z'):
if (ord(ch) - actual_shift_amount) >= ord('a'):
new_letter = chr(ord(ch) - actual_shift_amount)
else:
new_letter = chr(ord('z') - actual_shift_amount + (ord(ch) - ord('a') + 1))
elif ord('A') <= ord(ch) <= ord('Z'):
if (ord(ch) - actual_shift_amount) >= ord('A'):
new_letter = chr(ord(ch) - actual_shift_amount)
else:
new_letter = chr(ord('Z') - actual_shift_amount + (ord(ch) - ord('A') + 1))
res.append(new_letter)
return ''.join(res)
decode_or_encode = input("Would you like to encode or decode text? encode/decode: ").lower()
if decode_or_encode == "encode":
user_word = input("Enter in a word to encode: ")
print(encode(user_word))
elif decode_or_encode == "decode":
user_word = input("Enter in the encoded word: ")
print(decode(user_word))
Example Usage encode:
Would you like to encode or decode text? encode/decode: encode
Enter in a word to encode: Yoruke-Stack-Overflow
Aqtwmg-Uvcem-Qxgthnqy
Example Usage decode:
Would you like to encode or decode text? encode/decode: decode
Enter in the encoded word: Aqtwmg-Uvcem-Qxgthnqy
Yoruke-Stack-Overflow
Try it here.
The problem is that when adding or subtracting 2 you do not check if you reached the limit of the alphabet ('a' or 'z'). You should do something like
if encoded_letter > "z":
# do something
The approach you are following is not the best one. However, assuming that you are considering lowercase characters only.
Encoding
replacing
encoded_letter = chr(letter_ord + 2)
with
encoded_ord = letter_ord + 2
if encoded_ord > ord('z'): # after encoding if exceeds from 'z'
difference = encoded_ord - ord('z') # finding how much exceeded from 'z'
encoded_ord = ord('a') + difference + 1 # restart from 'a' again.
encoded_letter = chr(encoded_ord)
Decoding
replacing
decoded_letter = chr(letter_ord-2)
with
decoded_ord = letter_ord - 2
if decoded_ord < ord('a'): # after decoding if deceeds from 'a'
difference = ord('a') - decoded_ord # finding how much deceeded from 'a'
decoded_ord = ord('z') - difference + 1 # restart from 'z' again but backward
decoded_letter = chr(decoded_ord)
should work
So currently I am working on a Caesar cypher app, my code looks like this (coded by RAD software https://anvil.works/)
The problem is that I don't get any output when I try to run the program and I think that it could be self.text_area_2 = cipher_encrypt(plain_text, key). I'm not sure if I'm using the correct statement to display the output correctly.
What statement should I use instead? Am I doing the right thing?
from ._anvil_designer import Form2Template
from anvil import *
class Form2(Form2Template):
def __init__(self, **properties):
# Set Form properties and Data Bindings.
self.init_components(**properties)
def button_1_click(self, **event_args):
def cipher_encrypt(plain_text, key):
plain_text = self.text_area_1.text
key = self.text_box_1.text
encrypted = ""
for c in plain_text:
if c.isupper(): #check if it's an uppercase character
c_index = ord(c) - ord('A')
# shift the current character by key positions
c_shifted = (c_index + key) % 26 + ord('A')
c_new = chr(c_shifted)
encrypted += c_new
elif c.islower(): #check if its a lowecase character
# subtract the unicode of 'a' to get index in [0-25) range
c_index = ord(c) - ord('a')
c_shifted = (c_index + key) % 26 + ord('a')
c_new = chr(c_shifted)
encrypted += c_new
elif c.isdigit():
# if it's a number,shift its actual value
c_new = (int(c) + key) % 10
encrypted += str(c_new)
else:
# if its neither alphabetical nor a number, just leave it like that
encrypted += c
return encrypted
self.text_area_2 = cipher_encrypt(plain_text, key)
I am trying to make a simple Ceaser cipher and have it mostly working the way I want. Except, I want to only shift the letters in the message that are uppercase and keep the lowercase letters the same. For example, if the message is "HeLLo" the program should only shift "H LL" and keep "e o" the same. As shown below.
Current output:
Message: HeLLo
Shift: 1
IFMMP
Desired output:
Message: HeLLo
Shift: 1
IeMMo
The code:
plain_text = input("Message: ")
shift = int(input("Shift: "))
def caesar(plain_text, shift):
cipher_text = ""
for ch in plain_text:
if plain_text.lower():
plain_text = plain_text
if ch.isalpha():
final_letter = chr((ord(ch) + shift - ord('A')) % 26 + ord('A'))
cipher_text += final_letter
else:
cipher_text += ch
print(cipher_text)
return cipher_text
caesar(plain_text, shift)
You could add ch != ch.lower() condition to check that the character is not a lowercase character and encrypt it only when it isn't a lowercase character.
plain_text = input("Message: ")
shift = int(input("Shift: "))
def caesar(plain_text, shift):
cipher_text = ""
for ch in plain_text:
if ch.isalpha() and ch != ch.lower():
final_letter = chr((ord(ch) + shift - ord('A')) % 26 + ord('A'))
cipher_text += final_letter
else:
cipher_text += ch
print(cipher_text)
return cipher_text
caesar(plain_text, shift)
I think you need:
def caesar(plain_text, shift):
return "".join([chr(ord(i)+shift) if i.isupper() else i for i in plain_text])
caesar(plain_text, shift)
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.
I have a code and I'm having trouble making it interactive.
Here's the problem:
"""Write a function called rot13 that uses the Caesar cipher to encrypt a message. The Caesar cipher works like a substitution cipher but each character is replaced by the character 13 characters to βits rightβ in the alphabet. So for example the letter βaβ becomes the letter βnβ. If a letter is past the middle of the alphabet then the counting wraps around to the letter βaβ again, so βnβ becomes βaβ, βoβ becomes βbβ and so on. Hint: Whenever you talk about things wrapping around its a good idea to think of modulo arithmetic (using the remainder operator)."""
Here's the code to this problem:
def rot13(mess):
alphabet = 'abcdefghijklmnopqrstuvwxyz'
encrypted = ''
for char in mess:
if char == ' ':
encrypted = encrypted + ' '
else:
rotated_index = alphabet.index(char) + 13
if rotated_index < 26:
encrypted = encrypted + alphabet[rotated_index]
else:
encrypted = encrypted + alphabet[rotated_index % 26]
return encrypted
def main():
print(rot13('abcde'))
print(rot13('nopqr'))
print(rot13(rot13('since rot thirteen is symmetric you should see this message')))
if __name__ == "__main__":
main()
I want to make it interactive where you can input any message and you can rotate the letters however many times as you want. Here is my attempt. I understand you'd need two parameters to pass, but I'm clueless as to how to replace a few items.
Here's my attempt:
def rot13(mess, char):
alphabet = 'abcdefghijklmnopqrstuvwxyz'
encrypted = ''
for char in mess:
if char == ' ':
encrypted = encrypted + ' '
else:
rotated_index = alphabet.index(char) + mess
if rotated_index < 26:
encrypted = encrypted + alphabet[rotated_index]
else:
encrypted = encrypted + alphabet[rotated_index % 26]
return encrypted
def main():
messy_shit = input("Rotate by: ")
the_message = input("Type a message")
print(rot13(the_message, messy_shit))
if __name__ == "__main__":
main()
I don't know where my input should be taking place in the function. I have a feeling it could be encrypted?
This is probably what you're looking for. It rotates the message by the messy_shit input.
def rot13(mess, rotate_by):
alphabet = 'abcdefghijklmnopqrstuvwxyz'
encrypted = ''
for char in mess:
if char == ' ':
encrypted = encrypted + ' '
else:
rotated_index = alphabet.index(char) + int(rotate_by)
if rotated_index < 26:
encrypted = encrypted + alphabet[rotated_index]
else:
encrypted = encrypted + alphabet[rotated_index % 26]
return encrypted
def main():
messy_shit = input("Rotate by: ")
the_message = input("Type a message")
print(rot13(the_message, messy_shit))
def rot(message, rotate_by):
'''
Creates a string as the result of rotating the given string
by the given number of characters to rotate by
Args:
message: a string to be rotated by rotate_by characters
rotate_by: a non-negative integer that represents the number
of characters to rotate message by
Returns:
A string representing the given string (message) rotated by
(rotate_by) characters. For example:
rot('hello', 13) returns 'uryyb'
'''
assert isinstance(rotate_by, int) == True
assert (rotate_by >= 0) == True
alphabet = 'abcdefghijklmnopqrstuvwxyz'
rotated_message = []
for char in message:
if char == ' ':
rotated_message.append(char)
else:
rotated_index = alphabet.index(char) + rotate_by
if rotated_index < 26:
rotated_message.append(alphabet[rotated_index])
else:
rotated_message.append(alphabet[rotated_index % 26])
return ''.join(rotated_message)
if __name__ == '__main__':
while True:
# Get user input necessary for executing the rot function
message = input("Enter message here: ")
rotate_by = input("Enter your rotation number: ")
# Ensure the user's input is valid
if not rotate_by.isdigit():
print("Invalid! Expected a non-negative integer to rotate by")
continue
rotated_message = rot(message, int(rotate_by))
print("rot-ified message:", rotated_message)
# Allow the user to decide if they want to continue
run_again = input("Continue? [y/n]: ").lower()
while run_again != 'y' and run_again != 'n':
print("Invalid! Expected 'y' or 'n'")
run_again = input("Continue? [y/n]: ")
if run_again == 'n':
break
Note: It's more efficient to create a list of characters then join them to produce a string instead of using string = string + char. See Method 6 here and the Python docs here. Also, be aware that our rot function only works for lowercase letters of the alphabet. It'll break if you try to rot a message with uppercase characters or any character that isn't in alphabet.