I am working on an online course that has us creating a caesar cipher and vigenere cipher, but we first created two functions; one to find the position of a letter in an alphabet variable, and one to rotate one given character a given amount of times (I have seen that ord() and chr() work better, but the assignment wants us to focus on simpler concepts for now, I guess).
I was able to get the caesar function working, but am unsure as how to go forward with the vigenere cipher. I have watched many videos and looked around this site, but have not found any that allow for the preservation of spaces and non alphabetical characters. Can anyone point me in the right direction of how to start the vigenere function?
#Create function alphabet_position(letter) to turn letter into number
#such as a=0 or e=4, using lowercase to make sure case doesnt matter.
def alphabet_position(letter):
alphabet ="abcdefghijklmnopqrstuvwxyz" #Lists alphabet for a key
lower_letter = letter.lower() #Makes any input lowercase.
return alphabet.index(lower_letter) #Returns the position of input as a number.
def rotate_character(char, rot):
alphabet = "abcdefghijklmnopqrstuvwxyz"
if char.isalpha():
a = alphabet_position(char)
a = (a + rot) % 26 #needs modulo
a = (alphabet[a])
if char.isupper():
a = a.title()
return a
else:
return char
def encrypt(text, rot):
list1 = ""
for char in text:
list1 += rotate_character(char, rot)
return list1
def main():
x = input("Type a message: ")
y = input("Rotate by: ")
#result = rotate_character(x, y) #Not needed once encrypt function works.
result = encrypt(x, y)
print (result)
if __name__ == '__main__':
main()
following my comments; using all printables as alphabet:
from string import ascii_letters, digits, punctuation, whitespace
ALPHABET = ascii_letters + digits
STATIC_ALPHABET = punctuation + whitespace
# minor speedup
ALPHA_INDEX = {a: i for i, a in enumerate(ALPHABET)}
STATIC_ALPHABET_SET = set(STATIC_ALPHABET)
MOD = len(ALPHABET)
def encrypt(char, key):
if char in STATIC_ALPHABET_SET:
return char
else:
return ALPHABET[(ALPHA_INDEX[char] + key) % MOD]
def decrypt(char, key):
if char in STATIC_ALPHABET_SET:
return char
else:
return ALPHABET[(ALPHA_INDEX[char] + MOD - key) % MOD]
key = 17
plain = 'Hello World!'
enc = ''.join(encrypt(char, key) for char in plain)
print(enc) # YvCCF dFICu!
dec = ''.join(decrypt(char, key) for char in enc)
print(dec) # Hello World!
Related
So, this letter substitution cipher shows an error whenever there is a space (whitespace) in the input/phrase,to be encoded.
Here is my code:
Im quite new to python so it would be helpful for any suggestions whatsoever.
from string import ascii_lowercase
import random
EXAMPLE_KEY = ''.join(sorted(ascii_lowercase, key=lambda _:random.random()))
def encode(plaintext, key):
return ''.join(key[ascii_lowercase.index(char)] for char in plaintext)
def decode(plaintext, key):
return ''.join(ascii_lowercase[key.index(char)] for char in plaintext)
original = input("PLease enter a phrase: ")
encoded = encode(original, EXAMPLE_KEY)
decoded = decode(encoded, EXAMPLE_KEY)
print("The original is:", original)
print("Encoding it with the key:", EXAMPLE_KEY)
print("Gives:", encoded)
print("Decoding it by the same key gives:", decoded)
Note this isn't a Caesar Cipher, simply randomly changing the letters to other letters.
Thank you
ascii_lowercase does not contain a space, so ascii_lowercase.index(char) is a ValueError.
One reasonable approach is to just catch this error and return the same character. That would require breaking your join call out into a loop. You could shoehorn an if char in ascii_lowercase into there to keep it in one line, but that would be pretty ugly.
EDIT: like this
def encode(plaintext, key):
ret = ''
for char in plaintext:
try:
ret += key[ascii_lowercase.index(char)]
except ValueError:
ret += char
return ret
Hey so i'm trying to encrypt a string, with a shift key. It works perfectly, the only issue i have is with shifting the characters. For example hello, world!0 and the shift will be 5. I want it to return as olssv, dvysk!0 Basically, only the alphabets will get encrypted. The puncutations & numbers, etc won't be shifted.
keymax = 26
def text():
print('What message(s) are you trying to encrypt?')
return input()
def shift():
key = 0;
while True:
print('Enter the key number (1-%s)' % (keymax))
key = int(input())
if (key >= 1 and key <= keymax):
return key
def encrypt(string, shift):
hidden = ''
for char in string:
if char == ' ':
hidden = hidden + char
elif char.isupper():
hidden = hidden + chr((ord(char) + shift - 65) % 26 + 65)
else:
hidden = hidden + chr((ord(char) + shift - 97) % 26 + 97)
return hidden
text = text()
s = shift()
print("original string: ", text)
print("after encryption: ", encrypt(text, s))
I am fairly new to python, sorry for my bad understandings. Any help would gladly be appreciated!
You could replace the first if statement in your encrypt function with if char.isalpha() == False:. So when the character is not an alphabetical character, the charcter doesn't get changed.
Edit: Also to suggest an improvement, if you want to you can even have shifts upwards of 26. If you use key = key % 26 (%, called modulo, is the remainder of the division, in this case key divided by 26).
This allows you to have keys that are more than 26. This doesn't really change much at all, I just personally like it more
I am trying to decipher a text from user without knowing the key in caesar cipher.
I probably understand most of it but I don't get it why they use the mod 26 on line 8
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']
print('write the message you want to decode?')
inputString = input()
inputString = inputString.lower()
transAlphabet = {}
def createDict(shift):
for i in range(0,26):
letter = alphabet[i]
transAlphabet[letter]=alphabet[(i+shift)%26]
def encodeMessage(message):
cypherText = ''
for letter in message:
if letter in transAlphabet:
cypherText = cypherText + transAlphabet[letter]
else:
cypherText = cypherText + letter
print(cypherText)
for i in range(0,26):
createDict(i)
encodeMessage(inputString)
Please would be really helpful if someone helps me out thank you!
The modulo %26 is to make the alphabet circular, when you're at z come back at a
Example for alph[(i + shift) % 26] with i=20 and shift=10
without modulo you'll like to reach index 30 in the array and it doesn't not exist
with modulo you'll reach index 30%26 = 4 in the array, letter e
But also your algo is a bt strange, I would have done the shifting on the fly for each car, but your solution may be more efficient for long text as you don't need to compute the shift everytime.
Not computing the shifted alphabet before would look like this
from string import ascii_lowercase
alphabet = ascii_lowercase
def encode_message(message, shift):
cypher_text = ''
for letter in message:
letter_idx = alphabet.index(letter)
cypher_text = cypher_text + alphabet[(letter_idx + shift) % 26]
return cypher_text
def decode_message(message, shift):
cypher_text = ''
for letter in message:
letter_idx = alphabet.index(letter)
cypher_text = cypher_text + alphabet[(26 + letter_idx - shift) % 26]
return cypher_text
I struck a brick wall trying to solve this and I am not sure how to approach this problem.
My idea is to compare both first characters of each string and if they are the same, save the character in the alphabet string of the index position shift.
Recurse the rest of the string by removing the first character of the secret. If the first characters are different, recurse but removing the first character of the alphabet string.
I am not sure how to recurse for the rest of the alphabet though.
alphabet = "abcdefghijklmnopqrstuvwxyz"
def caesar_encrypt(secret, shift):
if len(secret) == 0:
return ""
elif shift == 0:
return secret
else:
if secret[0] == alphabet[0]:
return alphabet[shift] + caesar_encrypt(secret[1:],shift)
else:
return caesar_encrypt(secret,shift), alphabet[1:]
I would suggest using str.index to find the index of where each character is in the alphabet for each character in your string. After, use this to index into the alphabet and recurse.
A couple of gotchas that you should look out for:
If the string contains a space, place this space as is in the string then move onto the next character
You need to handle wraparound where if we're at the end of the alphabet and you choose a shift that would exceed the end of the alphabet, you need to wrap around and go to the beginning of the alphabet.
This should work:
alphabet = "abcdefghijklmnopqrstuvwxyz"
def caesar_encrypt(secret, shift):
if len(secret) == 0:
return ""
elif shift == 0:
return secret
elif secret[0] == ' ': # New - handle spaces
return ' ' + caesar_encrypt(secret[1:], shift)
else:
index = (alphabet.index(secret[0]) + shift) % len(alphabet) # Find the right place to access the alphabet
return alphabet[index] + caesar_encrypt(secret[1:], shift) # Use this new character then recurse
NB: This implementation only handles lowercase letters.
How about this:
def shift_alphabet(shift):
return alphabet[shift:] + alphabet[:shift]
def caesar_encrypt(secret, shift):
coded_alphabet = shift_alphabet(shift)
coded = [coded_alphabet[alphabet.index(i)] for i in secret]
coded = ''.join(coded)
return coded
Using map/lambda instead of for:
def shift_alphabet(shift):
return alphabet[shift:] + alphabet[:shift]
def encrypt_letter(letter, coded_alphabet):
return coded_alphabet[alphabet.index(letter)]
def caesar_encrypt(secret, shift):
coded_alphabet = shift_alphabet(shift)
coded = map(lambda x: encrypt_letter(x, coded_alphabet), secret)
coded = ''.join(coded)
return coded
I am currently trying to produce a program that allows me to encrypt and decrypt a words using a keyword, I have been told to use alphabetic value to do add from another words alphabetic value I know that I need to use ord or chr but I am not very confident in using this as I'm a beginner at programming, however I have no idea how to do this and would much appreciate, if someone could explain this to me with some examples.
s = "foo!#bar"
enc_key = "key"
# get sum of ord's of letters in key modulo 256
sm_ords= sum(map(ord,enc_key)) % 256
# add sum of ord's in encryption letter in key to ord of each char in s and use chr to create a new char
enc = "".join(chr((sm_ords + ord(ch))) for ch in s)
# reverse the encryption using - ord
dec = "".join(chr((ord(ch) - sm_ords)) for ch in enc)
print(enc)
print(dec)
¯¸¸jl«ª»
foo!#bar
This code encrypts / decrypts a string by adding the value of each of the keyword letters to each character in the string to be encrypted.
def encryptfunction():
result = ""
addedup = 0
for letter in wordtoencrypt:
for letter2 in keyword:
addedup = addedup + ord(letter2)
result = result + chr(ord(letter) + addedup)
return result
def decryptfunction():
result = ""
addedup = 0
for letter in wordtoencrypt:
for letter2 in keyword:
addedup = addedup + ord(letter2)
result = result + chr(ord(letter) - addedup)
return result
wordtoencrypt = input("Enter the word to encrypt:")
keyword = input("Enter the keyword:")
encrypt = int(input("encrypt(1) or decrypt(0)"))
if encrypt == 1:
print(encryptfunction())
else:
print(decryptfunction())