My ascii value dictionary doesn't work - python

I got an assignment yesterday about Rot and I was told to write all 26 of them in code, or atleast a program that did, so I thought I'd start with the dictionary, since I wanted to also call for a certain rot I came up with this.
def generate_rotated_dictionary(n):
for i in range(0, 26):
letter = alphabet_list[i]
new_let = ord(letter) + n
new_let = chr(new_let)
rot_dic.update({letter: new_let})
return(rot_dic)
Unfortunately, this doesn't work and results in:
{'a': 'b', 'c': 'd', 'b': 'c', 'e': 'f', 'd': 'e', 'g': 'h', 'f': 'g', 'i':
'j', 'h': 'i', 'k': 'l', 'j': 'k', 'm': 'n', 'l': 'm', 'o': 'p', 'n': 'o',
'q': 'r', 'p': 'q', 's': 't', 'r': 's', 'u': 'v', 't': 'u', 'w': 'x', 'v':
'w', 'y': 'z', 'x': 'y', 'z': '{'}
{'a': 'c', 'c': 'e', 'b': 'd', 'e': 'g', 'd': 'f', 'g': 'i', 'f': 'h', 'i':
'k', 'h': 'j', 'k': 'm', 'j': 'l', 'm': 'o', 'l': 'n', 'o': 'q', 'n': 'p',
'q': 's', 'p': 'r', 's': 'u', 'r': 't', 'u': 'w', 't': 'v', 'w': 'y', 'v':
'x', 'y': 'z', 'x': 'z', 'z': '|'}
{'a': 'd', 'c': 'f', 'b': 'e', 'e': 'h', 'd': 'g', 'g': 'j', 'f': 'i', 'i':
'l', 'h': 'k', 'k': 'n', 'j': 'm', 'm': 'p', 'l': 'o', 'o': 'r', 'n': 'q',
'q': 't', 'p': 's', 's': 'v', 'r': 'u', 'u': 'x', 't': 'w', 'w': 'z', 'v':
'y', 'y': '|', 'x': 'z', 'z': '}'}
{'a': 'e', 'c': 'g', 'b': 'f', 'e': 'i', 'd': 'h', 'g': 'k', 'f': 'j', 'i':
'm', 'h': 'l', 'k': 'o', 'j': 'n', 'm': 'q', 'l': 'p', 'o': 's', 'n': 'r',
'q': 'u', 'p': 't', 's': 'w', 'r': 'v', 'u': 'y', 't': 'x', 'w': 'z', 'v':
'z', 'y': '}', 'x': '|', 'z': '~'}
How do I fix it with the ending, I know that it is because of my use of Ascii values, but how do i get this to start with the a again (number 97)

So if you need to rotate alphabet you can use following method:
import string
alph = string.ascii_lowercase
for i in range(26):
print(''.join([alph[(k + i) % 26] for k in range(26)]))
Output is alphabetic strings with offset:
abcdefghijklmnopqrstuvwxyz
bcdefghijklmnopqrstuvwxyza
cdefghijklmnopqrstuvwxyzab
defghijklmnopqrstuvwxyzabc
.....
zabcdefghijklmnopqrstuvwxy
If you need lists instead of strings just remove join().
If you required some specific rotation like 13 then you can use this code inside function with argument:
def rot(i):
return ''.join([alph[(k + i) % 26] for k in range(26)])
This will give rotation for specific number.
Example:
print(rot(13))
Output:
nopqrstuvwxyzabcdefghijklm

l = list('abcdefghijklmnopqrstuvwxyz')
n = 1
rot = dict((c, chr(97 + ((ord(c)-97 + n)%26) )) for c in l)
The comprehension there is a little dense, so lets break it down:
(c, chr(97 + ((ord(c)-97 + n)%26) ))
produces tuples of one character and its shifted counterpart
chr(97 + ((ord(c)-97 + n)%26) )
makes a character
97 + (ord(c)-97 + n)%26
get the value of the old character and calculate how many to shift over.

So, in order to summarize, here's a full method:
# Generates a function which rotate a sequence by an offset
def generate_rot(seq, offset):
l = len(seq)
def rot(c):
n = (seq.index(c) + offset) % l
return seq[n]
return rot
> alpha = map(chr,range(97, 123)) # [a...z]
> rot13 = generate_rot(alpha, 13)
> print(rot13('a'))
n
> print(rot13('n'))
a
> rot21 = generate_rot(alpha, 21)
v
You can then bind it to the alphabet, specifically:
> def generate_alpha_rot(x):
return generate_rot(map(chr,range(97, 123)),x)
# or using a lambda function to create it inline, because why not?
> generate_alpha_rot = lambda x:generate_rot(map(chr,range(97, 123)),x)
> rot22 = generate_alpha_rot(22)
> rot22('a')
w
# Or call it inline:
> generate_alpha_rot(23)('a')
x

Hardly worth a full answer, but you want to take the modulo 26 of new_let before you convert to a character. by doing remainder division, you get how far past 26 the index has gone
Consider:
>>>26 + 13 # rot13 for z
39
>>>39 % 26
13

Related

Is there are more efficient method for creating a dictionary of letters mapped to letters shifted by a set integer?

I have written a function which takes an integer and returns a dictionary where the letters of the alphabet are mapped to an alphabet shifted by the integer. It has the requirement that lowercase and uppercase letters must correpsond, that is if a -> b then A->B.
I'm fairly new to python and have little experience with creating lists so I'm just wondering if there is an alternative more efficient or even just more elegant way to complete the same outcome.
import string
dictionary = []
for letter in string.ascii_lowercase + string.ascii_uppercase:
dictionary.append(letter)
def build_shift(shift):
shifted_dictionary = []
for i in range(0,26):
shifted_dictionary.append(dictionary[(i + shift) % 26])
for i in range(26, 53):
shifted_dictionary.append(dictionary[(( i + shift) % 26) + 26])
return (shifted_dictionary)
mapped_dictionary = dict( zip(dictionary, build_shift(2)))
print(mapped_dictionary)
You can use a dict comprehension that iterates characters over each of the lowercase and uppercase strings to output the character mapped to the one at the current index plus the offset and reduced with a modulo of 26. Below is an example using 2 as the offset:
{
c: s[(i + 2) % 26]
for s in (string.ascii_lowercase, string.ascii_uppercase)
for i, c in enumerate(s)
}
You can slice the string and get the desired result in less number of operations.
import string
shift = 2
changed_lc = f'{string.ascii_lowercase[shift:]}{string.ascii_lowercase[:shift]}'
changed_up = f'{string.ascii_uppercase[shift:]}{string.ascii_uppercase[:shift]}'
changed = f'{changed_lc}{changed_up}'
mapped_dictionary = dict(zip(string.ascii_letters, changed))
print(mapped_dictionary)
output:
{'a': 'c', 'b': 'd', 'c': 'e', 'd': 'f', 'e': 'g', 'f': 'h', 'g': 'i', 'h': 'j', 'i': 'k', 'j': 'l', 'k': 'm', 'l': 'n', 'm': 'o', 'n': 'p', 'o': 'q', 'p': 'r', 'q': 's', 'r': 't', 's': 'u', 't': 'v', 'u': 'w', 'v': 'x', 'w': 'y', 'x': 'z', 'y': 'a', 'z': 'b', 'A': 'C', 'B': 'D', 'C': 'E', 'D': 'F', 'E': 'G', 'F': 'H', 'G': 'I', 'H': 'J', 'I': 'K', 'J': 'L', 'K': 'M', 'L': 'N', 'M': 'O', 'N': 'P', 'O': 'Q', 'P': 'R', 'Q': 'S', 'R': 'T', 'S': 'U', 'T': 'V', 'U': 'W', 'V': 'X', 'W': 'Y', 'X': 'Z', 'Y': 'A', 'Z': 'B'}

Iterating over list

I am currently doing a small pet project and i have come this far, currently my code accepts the string, changes the string into the respective cipher and displays it but its displaying the whole iterated string. What i am doing wrong ? i want only the translated string.
Code
def encrypt_letter(letter):
cipher = {'a': 'n', 'b': 'o', 'c': 'p', 'd': 'q',
'e': 'r', 'f': 's', 'g': 't', 'h': 'u',
'i': 'v', 'j': 'w', 'k': 'x', 'l': 'y',
'm': 'z', 'n': 'a', 'o': 'b', 'p': 'c',
'q': 'd', 'r': 'e', 's': 'f', 't': 'g',
'u': 'h', 'v': 'i', 'w': 'j', 'x': 'k',
'y': 'l', 'z': 'm'}
lowercase_letter = letter.lower()
return cipher[lowercase_letter]
def encrypt(string):
result = []
letters = list(string)
for letter in letters:
encrypted_letter = encrypt_letter(letter)
result.append(encrypted_letter)
print "".join(result)
e = encrypt("hello")
print e
Output
u
ur
ury
uryy
uryyb
None
Expected output
'uryyb'
One minor change will do! What you want is to return the string.
def encrypt(string):
result = []
letters = list(string)
for letter in letters:
encrypted_letter = encrypt_letter(letter)
result.append(encrypted_letter)
return "".join(result) # change to return
e = encrypt("hello")
print e # will give you expected output
In fact, you can write shorter code with this:
def encrypt(string):
cipher = {'a': 'n', 'b': 'o', 'c': 'p', 'd': 'q',
'e': 'r', 'f': 's', 'g': 't', 'h': 'u',
'i': 'v', 'j': 'w', 'k': 'x', 'l': 'y',
'm': 'z', 'n': 'a', 'o': 'b', 'p': 'c',
'q': 'd', 'r': 'e', 's': 'f', 't': 'g',
'u': 'h', 'v': 'i', 'w': 'j', 'x': 'k',
'y': 'l', 'z': 'm'}
return ''.join(cipher[s] for s in string.lower())
You are printing out the list with each iteration of the for-loop. You need to do two things to fix the problem:
Dedent print "".join(result) one level.
In that line, change print to return.
Here is the full code:
def encrypt_letter(letter):
cipher = {'a': 'n', 'b': 'o', 'c': 'p', 'd': 'q',
'e': 'r', 'f': 's', 'g': 't', 'h': 'u',
'i': 'v', 'j': 'w', 'k': 'x', 'l': 'y',
'm': 'z', 'n': 'a', 'o': 'b', 'p': 'c',
'q': 'd', 'r': 'e', 's': 'f', 't': 'g',
'u': 'h', 'v': 'i', 'w': 'j', 'x': 'k',
'y': 'l', 'z': 'm'}
lowercase_letter = letter.lower()
return cipher[lowercase_letter]
def encrypt(string):
result = []
letters = list(string)
for letter in letters:
encrypted_letter = encrypt_letter(letter)
result.append(encrypted_letter)
######################
return "".join(result)
######################
e = encrypt("hello")
print e
Output:
uryyb
Your print is inside the for loop; dedent it one level, i.e.
result.append(encrypted_letter)
print "".join(result)
This will prevent the repeated printing out through the loop. Also, nothing gets returned from your function, add:
return result
at the end (either additional to or replacing the print) to send your output to e.
The problem is that
print "".join(result)
falls in the for loop.
def encrypt(string):
return ''.join([encrypt_letter(letter) for letter in string])
output:
uryyb
I'd return a string from encrypt, not print one.
def encrypt(string):
result = ""
for letter in list(string):
result += encrypt_letter(letter)
return result
print(encrypt("hello"))

Python Caesar cypher

I am trying to make a dict that can apply a Caesar Cypher to a letter.
I need it to be in one dict for upper and lower but cannot figure put how to get both into one dict.
import string
def Coder(shift):
alpha = string.ascii_lowercase
ALPHA = string.ascii_uppercase
if shift in range(0,26):
return dict(zip(ALPHA, ALPHA[shift:] + ALPHA[0:shift])), dict(zip(alpha, alpha[shift:] + alpha[0:shift]))
Something like this:
import string
def Coder(shift):
alpha = string.ascii_lowercase
ALPHA = string.ascii_uppercase
if 0 <= shift < 26:
unshifted_letters = ALPHA + alpha
shifted_letters = ALPHA[shift:] + ALPHA[:shift] + alpha[shift:] + alpha[:shift]
return dict(zip(unshifted_letters, shifted_letters))
But as others have said, better solutions are encode('rot13') and string.maketrans. In particular, this: "rot_13 rot13 Unicode string Returns the Caesar-cypher encryption of the operand".
If you're new to programming, avoid trying to "do everything on one line".
string.index( substring ) finds the position of substring in string.
a % b takes the remainder of a divided by b.
string.upper() returns an uppercased version of string.
Knowing this, you should be able to understand every line in this program:
import string
translation = {}
shift = 5
alphabet = string.ascii_lowercase
for letter in alphabet:
position = alphabet.index( letter )
new_position = (position + shift) % len( alphabet )
translation[ letter ] = alphabet[ new_position ]
translation[ letter.upper() ] = alphabet[ new_position ].upper()
You can use dict.update():
First create a dictionary of uppercase letters and then update that dict with a dictionary of lowercase letters:
In [8]: from string import *
In [9]: al=ascii_lowercase
In [10]: au=ascii_uppercase
In [11]: for shift in range(2):
dic1=dict(zip(au, au[shift:] + au[0:shift]))
dic1.update(dict(zip(al, al[shift:] + al[0:shift])))
print dic1
....:
{'A': 'A', 'C': 'C', 'B': 'B', 'E': 'E', 'D': 'D', 'G': 'G', 'F': 'F', 'I': 'I', 'H': 'H', 'K': 'K', 'J': 'J', 'M': 'M', 'L': 'L', 'O': 'O', 'N': 'N', 'Q': 'Q', 'P': 'P', 'S': 'S', 'R': 'R', 'U': 'U', 'T': 'T', 'W': 'W', 'V': 'V', 'Y': 'Y', 'X': 'X', 'Z': 'Z', 'a': 'a', 'c': 'c', 'b': 'b', 'e': 'e', 'd': 'd', 'g': 'g', 'f': 'f', 'i': 'i', 'h': 'h', 'k': 'k', 'j': 'j', 'm': 'm', 'l': 'l', 'o': 'o', 'n': 'n', 'q': 'q', 'p': 'p', 's': 's', 'r': 'r', 'u': 'u', 't': 't', 'w': 'w', 'v': 'v', 'y': 'y', 'x': 'x', 'z': 'z'}
{'A': 'B', 'C': 'D', 'B': 'C', 'E': 'F', 'D': 'E', 'G': 'H', 'F': 'G', 'I': 'J', 'H': 'I', 'K': 'L', 'J': 'K', 'M': 'N', 'L': 'M', 'O': 'P', 'N': 'O', 'Q': 'R', 'P': 'Q', 'S': 'T', 'R': 'S', 'U': 'V', 'T': 'U', 'W': 'X', 'V': 'W', 'Y': 'Z', 'X': 'Y', 'Z': 'A', 'a': 'b', 'c': 'd', 'b': 'c', 'e': 'f', 'd': 'e', 'g': 'h', 'f': 'g', 'i': 'j', 'h': 'i', 'k': 'l', 'j': 'k', 'm': 'n', 'l': 'm', 'o': 'p', 'n': 'o', 'q': 'r', 'p': 'q', 's': 't', 'r': 's', 'u': 'v', 't': 'u', 'w': 'x', 'v': 'w', 'y': 'z', 'x': 'y', 'z': 'a'}
or you can also use str.translate() with string.maketrans:
for shift in xrange(4):
t=maketrans(au+al,au[shift:]+au[:shift]+al[shift:]+al[:shift])
print "abcxyzABCXYZ".translate(t)
....:
abcxyzABCXYZ
bcdyzaBCDYZA
cdezabCDEZAB
defabcDEFABC
S.translate(table [,deletechars]) -> string
Return a copy of the string S, where all characters occurring in the
optional argument deletechars are removed, and the remaining
characters have been mapped through the given translation table, which
must be a string of length 256 or None. If the table argument is None,
no translation is applied and the operation simply removes the
characters in deletechars.

How to implement Caesar cipher [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Caesar’s Cipher using python, could use a little help
Alright, so in my class, I'm supposed to write code that shifts a dictionary as a Ceasar cipher. My code shifts everything fine, but returns the keys in a different order than the provided test case.
My code:
sLowerCase = string.ascii_lowercase
sUpperCase = string.ascii_uppercase
dCode = {'A':'A', 'B':'B', 'C':'C', 'D':'D', 'E':'E', 'F':'F', 'G':'G', 'H':'H', 'I':'I', 'J':'J', 'K':'K', 'L':'L', 'M':'M', 'N':'N', 'O':'O', 'P':'P', 'Q':'Q', 'R':'R', 'S':'S', 'T':'T', 'U':'U', 'V':'V', 'W':'W', 'X':'X', 'Y':'Y', 'Z':'Z',
'a':'a', 'b':'b', 'c':'c', 'd':'d', 'e':'e', 'f':'f', 'g':'g', 'h':'h', 'i':'i', 'j':'j', 'k':'k', 'l':'l', 'm':'m', 'n':'n', 'o':'o', 'p':'p', 'q':'q', 'r':'r', 's':'s', 't':'t', 'u':'u', 'v':'v', 'w':'w', 'x':'x', 'y':'y', 'z':'z'}
for c in dCode.keys():
if c in sUpperCase:
if sUpperCase.index(c) + shift > 25:
dCode[c] = sUpperCase[(sUpperCase.index(c) + shift) - 26]
else:
dCode[c] = sUpperCase[(sUpperCase.index(c) + shift)]
if c in sLowerCase:
if sLowerCase.index(c) + shift > 25:
dCode[c] = sLowerCase[(sLowerCase.index(c) + shift) - 26]
else:
dCode[c] = sLowerCase[(sLowerCase.index(c) + shift)]
return dCode
My output for buildCoder(0) (easiest to read obviously)
{'B': 'B', 'D': 'D', 'F': 'F', 'H': 'H', 'J': 'J', 'L': 'L', 'N': 'N', 'P': 'P', 'R': 'R', 'T': 'T', 'V': 'V', 'X': 'X', 'Z': 'Z', 'b': 'b', 'd': 'd', 'f': 'f', 'h': 'h', 'j': 'j', 'l': 'l', 'n': 'n', 'p': 'p', 'r': 'r', 't': 't', 'v': 'v', 'x': 'x', 'z': 'z', 'A': 'A', 'C': 'C', 'E': 'E', 'G': 'G', 'I': 'I', 'K': 'K', 'M': 'M', 'O': 'O', 'Q': 'Q', 'S': 'S', 'U': 'U', 'W': 'W', 'Y': 'Y', 'a': 'a', 'c': 'c', 'e': 'e', 'g': 'g', 'i': 'i', 'k': 'k', 'm': 'm', 'o': 'o', 'q': 'q', 's': 's', 'u': 'u', 'w': 'w', 'y': 'y'}
Their output:
{'A': 'A', 'C': 'C', 'B': 'B', 'E': 'E', 'D': 'D', 'G': 'G', 'F': 'F', 'I': 'I', 'H': 'H', 'K': 'K', 'J': 'J', 'M': 'M', 'L': 'L', 'O': 'O', 'N': 'N', 'Q': 'Q', 'P': 'P', 'S': 'S', 'R': 'R', 'U': 'U', 'T': 'T', 'W': 'W', 'V': 'V', 'Y': 'Y', 'X': 'X', 'Z': 'Z', 'a': 'a', 'c': 'c', 'b': 'b', 'e': 'e', 'd': 'd', 'g': 'g', 'f': 'f', 'i': 'i', 'h': 'h', 'k': 'k', 'j': 'j', 'm': 'm', 'l': 'l', 'o': 'o', 'n': 'n', 'q': 'q', 'p': 'p', 's': 's', 'r': 'r', 'u': 'u', 't': 't', 'w': 'w', 'v': 'v', 'y': 'y', 'x': 'x', 'z': 'z'}
I've already used python to test and compare and they are indeed dicts comprised of the same keys:values. Any advice would be grand. (This is for an online MIT class. There are normally forums, but they are down while there is an exam available. This is NOT for the exam,
Dictionaries in Python don't preserve a particular order. So you can't be sure that the keys and values will be read in the order that they were (a) originally created or (b) last updated.
Quite obviously, the two dictionaries are the same though.
Edit: dict1 == dict2 is sufficient to prove whether two dictionaries are the same; you don't have to check each key/value piecewise.
Just another note, you should be using the modulus % operator instead of - 26.
Replace
if sUpperCase.index(c) + shift > 25:
dCode[c] = sUpperCase[(sUpperCase.index(c) + shift) - 26]
else:
dCode[c] = sUpperCase[(sUpperCase.index(c) + shift)]
With
dCode[c] = sUpperCase[(sUpperCase.index(c) + shift) % 26]

Why my code prints others characters? cipher

I want print only letters but it's prints special characters of ASCII. My code:
import string
def caesar(shift):
alphabet = string.ascii_lowercase + string.ascii_uppercase
dict={}
emptylist=[]
int(shift)
for x in alphabet:
emptylist.append(x)
code = ""
for letters in emptylist:
code = chr(ord(letters) + shift)
dict[letters]=code
return dict
caesar(12)
My output:
'm': 'y', 'l': 'x', 'o': '{', 'n': 'z', 'q': '}', 'p': '|', 's': '\x7f', 'r': '~', 'u': '\x81', 't': '\x80', 'w': '\x83', 'v': '\x82', 'y': '\x85', 'x': '\x84', 'z': '\x86'
Correct output:
'm': 'y', 'l': 'x', 'o': 'a', 'n': 'z', 'q': 'c', 'p': 'b', 's': 'e', 'r': 'd', 'u': 'g', 't': 'f', 'w': 'i', 'v': 'h', 'y': 'k', 'x': 'j', 'z': 'l'
Using ord() and changing the character code won't restrict the resulting character to your dictionary.
I'd just find the index of the letter in your dictionary, shift it, and use the modulo operator:
import string
def caesar(shift):
alphabet = string.ascii_uppercase # <- Change it back to what you had before
# and see what will happen.
mapping = {}
for letter in alphabet:
index = alphabet.index(letter)
mapping[letter] = alphabet[(index + shift) % len(alphabet)]
return mapping
Test (dictionaries don't preserve order, so it's pretty hard to read):
>>> caesar(12)
{'A': 'M', 'C': 'O', 'B': 'N', 'E': 'Q', 'D': 'P', 'G': 'S', 'F': 'R', 'I': 'U', 'H': 'T', 'K': 'W', 'J': 'V', 'M': 'Y', 'L': 'X', 'O': 'A', 'N': 'Z', 'Q': 'C', 'P': 'B', 'S': 'E', 'R': 'D', 'U': 'G', 'T': 'F', 'W': 'I', 'V': 'H', 'Y': 'K', 'X': 'J', 'Z': 'L'}
Let's look at one error in particular: o: '{'.
Notice that ord('o') is 111, so let's look at the chr of integers in the range(111,130):
Starting at o, shifting by 12, takes you to the { character:
In [75]: ' '.join([chr(x) for x in range(111,130)])
Out[75]: 'o p q r s t u v w x y z { | } ~ \x7f \x80 \x81'
^ 1 2 3 4 5 6 7 8 9 ...12
So the reason why you are getting incorrect output is because your formula
code = chr(ord(letters) + shift)
isn't taking into account what happens if the shift bounces you out of the ords associated with a-z or A-Z. (Note that the ord ranges for a-z and A-Z are not contiguous either!)
Here is a hint on how to fix:
In [82]: alphabet = string.ascii_lowercase + string.ascii_uppercase
In [83]: alphabet.index('o')
Out[83]: 14
In [84]: alphabet[alphabet.index('o')+12]
Out[84]: 'A'
but
In [85]: alphabet[alphabet.index('O')+12]
results in IndexError: string index out of range. That's because len(alphabet) is 52, and
In [91]: alphabet.index('O')+12
Out[91]: 52
Somehow we need 52 to wrap back around to 0. You can do that with the % modulo operator:
In [92]: 52 % 52
Out[92]: 0

Categories

Resources