Caesar Cipher shift by two letters - python

def main():
cc = (input("Enter Message to Encrypt\n"))#user input
shift = int(2) #shift length
a=["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"] #reference list
newa={} #new shifted reference list
for i in range (0,len(a)):
newa [a[i]]=a[(i+shift)%len(a)]
#adds shifted 2 alaphabet into newalaphabet
#% moodulus used to wrap
for i in cc: #iterates through cc
if i in a:
a[i]=cc[i]
a[i]=newa[i]
main()
So I need input from the user #cc
the shift needs to be two
I used an alphabet list
then shift the alphabet by two to create newa
but I do not know how to apply the new alphabet to my user's input

Use a dictionary to map inputs to outputs
shifted_a = a[-shift:] + a[:-shift]
cipher = {a[i]: shifted_a[i] for i in range(len(a))}
output = ''.join(cipher[char] for char in cc)

Iterate through the string cc and replace all the alphabets using the get method of newa. Characters that are not in the dictionary are left as is, by passing them as the default to newa.get when the key is missing:
newa = {}
for i, x in enumerate(a):
newa[x] = a[(i+shift) % len(a)]
encrypted_text = ''.join(newa.get(i, i) for i in cc)
Python's builtin enumerate can be used in place of range(len(a)) in this case where you need the items in a and their respective indices.

Use mapping for every char, then join them back to create the encrypted message:
''.join(map(lambda x: chr((ord(x) - 97 + shift) % 26 + 97) if x in alphabet else x, cc.lower()))
Integrate it like that:
import string
alphabet = string.ascii_lowercase
cc = input('Enter string to encode: ')
shift = 2 # could be any number
encrypted = ''.join(map(lambda x: chr((ord(x) - 97 + shift) % 26 + 97) if x in alphabet else x, cc.lower()))
cc.lower() for the letters to be all same case (to map using constant ord)
chr((ord(x) - 97 + shift) % 26 + 97) :
get the value of the number minus 97 (0 for a, 1 for b, etc.).
apply the shift (a turns to c, etc.).
modulate by 26 to prevent letters like z from exceeding (25 + 2 = 27, 27 % 26 = 1 = b).
add 97 to bring the letter back to ascii standard (97 for a, 98 for b, etc.)
if x in alphabet else x cover for signs that are not letter (if you want to ignore spaces and punctuation use if x in alphabet else '' instead).

I would just build transition table and use it to decode string.
import string
shift = 2
letters = string.ascii_lowercase + string.ascii_uppercase
transtable = str.maketrans({letters[i]: letters[(i + shift) % len(letters)]
for i in range(len(letters))})
cc = input('Enter string to encode: ')
print(cc.translate(transtable))

I'll throw my solution in there. It should be pretty clear how it works...
import string
index_lookup = {letter: index for index, letter in enumerate(string.ascii_lowercase)}
def caesar_letter(l, shift=2):
new_index = index_lookup[l] + shift
return string.ascii_lowercase[new_index % len(index_lookup)]
def caesar_word(s):
return ''.join([caesar_letter(letter) for letter in s])
I think the above is better for readability but if you're opposed to imports...
index_lookup = {chr(idx): idx - ord('a') for idx in range(ord('a'), ord('z')+1)}
...
In [5]: caesar_word('abcdefghijklmnopqrstuvwxyz')
Out[5]: 'cdefghijklmnopqrstuvwxyzab'

Related

How to check if a value exists in a list, and store the elements that include it in variables

I'm trying to make an encrypter, where it shifts the letter 3 times (so A becomes D, B becomes E, etc.)
Then X goes back to A, Y to B, and Z to C. I'm using ASCII values to shift them. I'm trying to see if any part of the list has the ASCII values of X, Y, or Z, then if yes, change that element back to A, B, or C's ASCII value.
I know you can check if there is a value in a list, but how do I actually take this value and change it? Here is what I'm trying to do:
Check if X/Y/Z's ASCII code exists in the user_input list
If true, get that value and change it back into A/B/C's ASCII value accordingly.
Here is my code:
def encrypt(userInput):
#Find Ascii Value of plaintext
asciiValue = [ord(c) for c in userInput]
#Convert Ascii value (list) into integers
intAscii = [int(x) for x in asciiValue]
encryptedAscii = [n + 3 for n in intAscii]
if '120' in encryptedAscii:
encryptedAscii = '97'
elif '121' in encryptedAscii:
encryptedAscii = '98'
elif '122' in encryptedAscii:
encryptedAscii = '99'
else:
encryptedOutput = ''.join(chr(v) for v in encryptedAscii)
return encryptedOutput
Thanks!
You actually don't need to check for x, y, z separately. Just use the modulo operator (%) so if it overflows, it will turn back to a, b, c:
def encrypt(userInput):
# Find Ascii Value of plaintext
asciiValue = [ord(c) for c in userInput]
# Convert Ascii value (list) into integers
intAscii = [int(x) - 97 for x in asciiValue]
encryptedAscii = [(n + 3) % 26 + 97 for n in intAscii]
encryptedOutput = ''.join(chr(v) for v in encryptedAscii)
return encryptedOutput
from string import ascii_lowercase
print(encrypt(ascii_lowercase))
Output:
defghijklmnopqrstuvwxyabc
Using ord and chr is fine, but there is also an easier method: str.maketrans and str.translate:
from string import ascii_uppercase as ABC, ascii_lowercase as abc
def encrypt(text, tr):
return text.translate(tr)
# join translation dicts for ABCD and abcs to
# create mapping from 2 strings of equal lenght,
# first is "from" second is "to" mapping:
tr = {**str.maketrans(abc, abc[3:]+abc[:3]), # lower case a-z
**str.maketrans(ABC, ABC[3:]+ABC[:3])} # upper case A-Z
text = "ABCDEFGXYZabcdefgxyz"
print(text, " => ", encrypt(text,tr))
Output:
ABCDEFGXYZabcdefgxyz => DEFGHIJABCdefghijabc

How to encode (hash) a big string into a 4 letter string?

I want to build an ID for each row of a datatable based on entries in multiple columns.
How to proceed in order to convert a long string, let's say hello2017good into a 3 or 4 letter string that can have only letters but uppercase/lowercase both allowed ?
Take a standard hash algorithm, like sha1, and use the random array of bytes returned to index into a table of a to z (and A-Z).
import hashlib
h = hashlib.sha1(b"hello2017good")
d = h.digest()
s = ""
for i in range(0,4):
x = d[i] % 52
if x >= 26:
s += chr(ord('A') + x - 26)
else:
s += chr(ord('a') + x)
print(s)

Python Simple Encryption program: How to loop Z back to A

I'm trying to make an encryption function that encrypts plaintext messages but the problem is that if i input a key too large that goes past 'Z' then it goes onto greater unicode values.
My code:
def encrypt(var1,var2):
var3 = ""
for i in range(0, len(var1)):
if ord(var1[i])>64 and ord(var1[i])<90:
var3=var3+chr((ord(var1[i])+var2))
elif ord(var1[i])+var2>90:
???
else:
continue
return(var3)
How do I get it to loop 'Z' back to 'A'. I think I have to make an if statement like this but I'm not sure what to put into it.
elif ord(var1[i])+var2>90:
???
Here is my one! Im using the modulus operator to wrap around every 26 numbers (the number of letter between a-z). I also handle upper on lowercase separately.
def encrypt(data, shift):
result = ''
for c in data:
c_num = ord(c)
# is the letter lower case a - z?
if (c_num >= ord('a')) and (c_num <= ord('z')):
# get the letter number from 0 - 26
c_num = c_num - ord('a')
# shift the number
c_num += shift
# wrap the number every 26 numbers
c_num = c_num % 26
# now increase a by the new amount
c_num += ord('a')
result += chr(c_num)
# is the letter upper case A - Z?
elif (c_num >= ord('A')) and (c_num <= ord('Z')):
# get the letter number from 0 - 26
c_num = c_num - ord('A')
# shift the number
c_num += shift
# wrap the number every 26 numbers
c_num = c_num % 26
# now increase a by the new amount
c_num += ord('A')
result += chr(c_num)
return result
encrypt('aAbB', 2)
'cCdD'
encrypt('afZz', 2)
'chBb'
Here is the code golf version using list comprehension just for fun!
def encrypt(data, shift):
return ''.join([chr(((ord(c) - ord('a') + shift) % 26) + ord('a')) if ord(c) in range(ord('a'), ord('z')+1) else chr(((ord(c) - ord('A') + shift) % 26) + ord('A')) for c in data])
A straight-forward way would be to check if you have passed beyond Z, and modify the character in that case:
...
if var1[i] >= 'A' and var1[i] <= 'Z':
translated_char = chr(ord(var1[i])+var2)
if translated_char > 'Z':
# If the resulting character is beyond Z,
# we go 26 characters back
translated_char = chr(ord(translated_char)-26)
# Append the translated character to the output string
var3 += translated_char
...
You may want to consider more descriptive variable names -- you'll thank yourself if you revisit your code after two months :-)
I would recommend using the modulus operator to do what you are wanting. In python that is the % character. In modulus math. X % Y tells us what the remainder of X / Y is. For example. 27 % 26 is 1. Using this you can get your wrap around that you want. Here is a sample bit of code to encrypt a single character
def encrypt_character( valToEncrypt, keyVal ):
# Update the character to be our standard Alphabet mapping
# A -> 0; B->1 ... Z -> 25
x = ord(valToEncrypt) - ord('A')
# Perform the Encryption
retVal = ( x + keyVal ) % 26
# Translate back to the standard ASCII mapping of the character
# for display in python and translate it back into a string
retVal = chr(retVal + ord('A'))
return retVal
# end encrypt_character
Now if we feed the character "A" Into our encryption algorithm with a key of 13 we get "N" as shown:
>>> encrypt_character("A", 13)
'N'
The decrypt algorithm is very similar, except you do subtraction instead of addtion
def decrypt_character( valToDecrypt, keyVal ):
# Update the character to be our standard Alphabet mapping
# A -> 0; B->1 ... Z -> 25
x = ord(valToDecrypt) - ord('A')
retVal = ( x - keyVal ) % 26
# Translate back to the standard ASCII mapping of the character
# for display in python and translate it back into a string
retVal = chr(retVal + ord('A'))
return retVal
To encrypt a string you can use the following function:
from re import sub
def encrypt_message( message, key ):
# Convert the message text into a plain text with all spaces and
# punctuation removed.
plainText = sub(r'[^A-Z]', '', message.upper())
cipherText = ""
charIndex = 0
# Encrypt the message 1 character at a time
while charIndex < len(plainText):
cipherText += \
encrypt_character( plainText[charIndex], key)
charIndex += 1
return cipherText
This function can be called:
>>> encrypt_message("HELLO World!", key=23)
'EBIILTLOIA'
The decryption function is very similar to the encryption function, except it calls the decrypt utility instead of the encrypt utility.

Caesar Shift on list elements using list comprehension

I am very new to Python and have run into a road block. Is it possible to use list comprehension to perform a shift on each letter of a word in a list? Also how could I utilize ord() and chr() in a similar list comprehension manner?
So far I have the following code:
def shift( file1="file1.txt", file2 ="file2.txt"):
key = int(input("Enter shift key: "))
with open(" file1. txt") as readfile:
lines = readfile.readlines()
lines = [words.lower() for words in lines]
lines = [ words.split(" ") for words in lines]
All I need now is to perform the actual shift but I am stumped :/
Here is a simple Caesar Shift using a comprehension:
>>> string = 'CaesarShift'; shift=3
>>> ''.join(chr(ord('a') + (ord(c)-ord('a')+shift) % 26) for c in string)
'zdhvdupkliw'
This illustrates the concept but makes no attempt to handle spaces or punctuation.
Reversibility
>>> new = ''.join(chr(ord('a') + (ord(c)-ord('a')+shift) % 26) for c in string.lower())
>>> ''.join(chr(ord('a') + (ord(c)-ord('a')-shift) % 26) for c in new)
'caesarshift'
You can use str.join , iterating over each ch/character in each word from the word_list, you can use whatever formula you have to create your cipher.
word_list = ["Foo","Bar","Foobar"]
print(["".join(chr(ord(ch) + 10) for ch in word.lower()) for word in word_list ])
['pyy', 'lk|', 'pyylk|']
Wrap Around: The Caesar Shift is a wrap-around shift cipher, so you have to have an algorithm to wrap around strings.
If you consider letters as numbers, then you could write the letters out as [0, 1 ... 25], i.e. range(26).
If you do a Caesar shift of 10 on this, you will get: [10, 11 ... 25, 26 ... 35].
Character 26 isn't in the alphabet. You will need to change this to 0. Then change character 27 to 1, and so on. So, the transformation you are looking for, (if the alphabet was arranged from 0 to 25) is, mod( letterValue + 10, 26).
However, the letters do not start from 0, so you will have to first subtract the value of ord('a') and then add it later.
The letterValue in the above expression is simply: ord(ch) - ord('a'). So change the earlier expression to (chr(ch) - ord('a') + 10) % 26.
Then change it back using: chr((chr(ch) - ord('a') + 10) % 26 + ord('a')).
Since ord('a') is 96, you can speed up this process a little by using: chr((chr(ch) - 96 + 10)%26 + 96), i.e., chr((chr(ch)-86)%26 + 96)
Non alphabetic characters: What will characters such as ? and ! translate to? These generally go through unaltered. You can supply that with an if condition and check if the requested character is in string.ascii_lowercase.
Something like:
from string import ascii_lowercase as lowerLetters
def toCaesar(ch):
if ch in lowerLetters:
return chr((chr(ch) - 86)%26 + 96)
else:
return ch
The rest I think you already have.

How can I increment a char?

I'm new to Python, coming from Java and C. How can I increment a char? In Java or C, chars and ints are practically interchangeable, and in certain loops, it's very useful to me to be able to do increment chars, and index arrays by chars.
How can I do this in Python? It's bad enough not having a traditional for(;;) looper - is there any way I can achieve what I want to achieve without having to rethink my entire strategy?
In Python 2.x, just use the ord and chr functions:
>>> ord('c')
99
>>> ord('c') + 1
100
>>> chr(ord('c') + 1)
'd'
>>>
Python 3.x makes this more organized and interesting, due to its clear distinction between bytes and unicode. By default, a "string" is unicode, so the above works (ord receives Unicode chars and chr produces them).
But if you're interested in bytes (such as for processing some binary data stream), things are even simpler:
>>> bstr = bytes('abc', 'utf-8')
>>> bstr
b'abc'
>>> bstr[0]
97
>>> bytes([97, 98, 99])
b'abc'
>>> bytes([bstr[0] + 1, 98, 99])
b'bbc'
"bad enough not having a traditional for(;;) looper"?? What?
Are you trying to do
import string
for c in string.lowercase:
...do something with c...
Or perhaps you're using string.uppercase or string.letters?
Python doesn't have for(;;) because there are often better ways to do it. It also doesn't have character math because it's not necessary, either.
Check this: USING FOR LOOP
for a in range(5):
x='A'
val=chr(ord(x) + a)
print(val)
LOOP OUTPUT: A B C D E
I came from PHP, where you can increment char (A to B, Z to AA, AA to AB etc.) using ++ operator. I made a simple function which does the same in Python. You can also change list of chars to whatever (lowercase, uppercase, etc.) is your need.
# Increment char (a -> b, az -> ba)
def inc_char(text, chlist = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'):
# Unique and sort
chlist = ''.join(sorted(set(str(chlist))))
chlen = len(chlist)
if not chlen:
return ''
text = str(text)
# Replace all chars but chlist
text = re.sub('[^' + chlist + ']', '', text)
if not len(text):
return chlist[0]
# Increment
inc = ''
over = False
for i in range(1, len(text)+1):
lchar = text[-i]
pos = chlist.find(lchar) + 1
if pos < chlen:
inc = chlist[pos] + inc
over = False
break
else:
inc = chlist[0] + inc
over = True
if over:
inc += chlist[0]
result = text[0:-len(inc)] + inc
return result
There is a way to increase character using ascii_letters from string package which ascii_letters is a string that contains all English alphabet, uppercase and lowercase:
>>> from string import ascii_letters
>>> ascii_letters[ascii_letters.index('a') + 1]
'b'
>>> ascii_letters
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
Also it can be done manually;
>>> letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
>>> letters[letters.index('c') + 1]
'd'
def doubleChar(str):
result = ''
for char in str:
result += char * 2
return result
print(doubleChar("amar"))
output:
aammaarr
For me i made the fallowing as a test.
string_1="abcd"
def test(string_1):
i = 0
p = ""
x = len(string_1)
while i < x:
y = (string_1)[i]
i=i+1
s = chr(ord(y) + 1)
p=p+s
print(p)
test(string_1)

Categories