Python Dictionary file not translating into array - python

I'm loading a file with words and definitions each on their own line separated by colons. Here is a sample.
Dissaray:A state of confusion and disorderliness
Staid:Steady and serious
Contemptible:Unworthy, wretched, mean
Intertwine:To connect or associate two things
Unwarranted:Not based on truth or valid circumstances
Punctuate:To specifically point out
Validate:To state the soundness or truth of something
Conducive:To contribute in a useful way
I'm trying to read the file with this code:
print("Currently loading file for your level")
dictionary = {}
with open("level"+str(level)+".txt","r+") as f:
for line in f:
print line
line.split(":")
dictionary[line[0]] = line[1]
print("Dictionary file has been loaded")
print(dictionary)
The lines print correctly, but when I print the dictionary array, I get this.
{'A': 'p', 'C': 'o', 'B': 'e', 'E': 'm', 'D': 'e', 'G': 'r', 'F': 'i', 'I': 'r', 'H': 'i', 'J': 'o', 'M': 'i', 'L': 'u', 'O': 'p', 'N': 'o', 'P': 'a', 'S': 'u', 'R': 'e', 'U': 'n', 'T': 'r', 'W': 'a', 'V': 'e', 'Z': 'e'}
I'm not sure what's happening here, can someone please help?

str.split doesn't work in place. You need to assign it to line, otherwise, you'll be indexing the original line:
for line in f:
line = line.split(":")
dictionary[line[0]] = line[1]
More so, you could also simply do:
dictionary = dict(line.split(':') for line in f)
Building the dictionary from a generator expression.

The problem is that .split() returns its value rather than modifying its argument. Actually it has to do that, because strings are immutable in Python. So you just need to change:
line.split(":")
dictionary[line[0]] = line[1]
to
line_parts = line.split(":")
dictionary[line_parts[0]] = line_parts[1]

Related

decrypting song with dictionary values

Hi I want to decrypt the song down below, but when I replace some word
and I keep moving forward in the dictionary keys, I lose my replacement.
For example, when 'O' turns to 'A' it is ok but, when the code continues
the dictionary value in 'A' = 'U'.
So I lose the correct replacement, and I get a wrong answer.
decryption_key = {
'O': 'A', 'D': 'B', 'F': 'C', 'I': 'D', 'H': 'E',
'G': 'F', 'L': 'G', 'C': 'H', 'K': 'I', 'Q': 'J',
'B': 'K', 'J': 'L', 'Z': 'M', 'V': 'N', 'S': 'O',
'R': 'P', 'M': 'Q', 'X': 'R', 'E': 'S', 'P': 'T',
'A': 'U', 'Y': 'V', 'W': 'W', 'T': 'X', 'U': 'Y',
'N': 'Z',
}
SONG = """
sc, kg pchxh'e svh pckvl k covl svps
pcop lhpe zh pcxsalc pch vklcp
k okv'p lsvvo is wcop k isv'p wovp ps
k'z lsvvo jkyh zu jkgh
eckvkvl jkbh o ikozsvi, xsjjkvl wkpc pch ikfh
epovikvl sv pch jhilh, k ecsw pch wkvi csw ps gju
wchv pch wsxji lhpe kv zu gofh
k eou, coyh o vkfh iou
coyh o vkfh iou
"""
SONG = SONG.upper()
for word, value in decryption_key.items():
if word in SONG:
SONG = SONG.replace(word, value)
else:
continue
print(SONG)
One workaround could be:
SONG = SONG.replace(word, value.lower())
This way, letters that are replaced will be lowercased and won't be affected later.
But a proper way would be constructing a new string:
SONG = ''.join(decryption_key.get(c, c) for c in SONG)
This just replaces your whole loop.
decryption_key.get(c, c) part might be confusing, but what it does is it returns the value by the given key if it exists in decryption_key or returns the key itself (as it was specified as a default by the second parameter) otherwise.

Decoding message using dictionary on string in Python

When I'm using a dictionary to replace values in a string for decoding of a message, how do I put it in such that the function doesn't read a replaced value as a key and replace a replaced value again?
def decipher_message(translation_guide, message):
t = read_translation_guide_into_dictionary(translation_guide)
e = read_message(message)
print(t)
print(e)
for key, value in t.items():
f = e
e = f.replace(key, value)
return e
Output:
{'a': 'm', 'b': 'a', 'c': 'c', 'd': 'y', 'e': 't', 'f': 'v', 'g': 'o',
'h': 'u', 'i': 'x', 'j': 'e', 'k': 'j', 'l': 'w', 'm': 'f', 'n': 'z',
'o': 'd', 'p': 'l', 'q': 'i', 'r': 'k', 's': 'h', 't': 'n', 'u': 'g',
'v': 'b', 'w': 'q', 'x': 's', 'y': 'p', 'z': 'r'}
"qa mqtbppd vjqtu mghto! esbtr dgh mgz mqtoqtu aj gs rqto xezbtujz. q
ahxe ejpp dgh, qex whqej vgzqtu sbfqtu bpp esj ljbpes qt esj lgzpo. qm
dghzj pggrqtu mgz qe, q vhzqjo b aby eg qe bzghto lsjzj dghzj xebtoqtu
tgl! zjajavjz esghus: ljbpes qxte jfjzdesqtu qt esj lgzpo!"
'"if finallp being fdgnd! nhank pdg fdr finding fe dh kind snranger. i
fgsn nell pdg, ins qgine bdring habing all nhe qealnh in nhe qdrld. if
pdgre lddking fdr in, i bgried a fap nd in ardgnd qhere pdgre snanding
ndq! refefber nhdggh: qealnh isnn eberpnhing in nhe qdrld!"'
Rather than iterating through the dictionary and running a replace against the whole string, you should iterate through the string and replace each character with its value in the dict:
decoded = []
for letter in e:
decoded.append(t.get(letter, letter))
return ''.join(decoded)
Note also that Python has a built-in string translate method, which takes a table which can be generated from your dict:
table = str.maketrans(t)
return e.translate(table)
You can use str.join with the following generator expression that iterates over the string to translate each character:
def decipher(translation, message):
t = read_translation(translation)
e = read_message(message)
return ''.join(t.get(c, c) for c in e)

list comprehension that makes use of a dictionary and if else statements

I am a beginner to list comprehension and am having trouble figuring something out. According to examples I have looked at on stackoverflow and other sites, I have a list comprehension that seems like it should work, but I have not been able to accomplish the desired output, as I have been unable to figure out the correct syntax for what I want to accomplish.
Given a string, I would like my function to return the string with the alpha characters replaced with the value associated with a key in the provided dictionary. For that task my list comprehension works, but I also need any characters and spaces to stay intact (no change).
Here is what I have tried:
#random dictionary for my example
d = {'a': 'b', 'c': 'i', 'b': 'a', 'e': 'j', 'd': 'm', 'g': 'q','f': 'l',
'i': 'c', 'h': 'w', 'k': 'r', 'j': 'e', 'm': 'd','l': 'f', 'o': 'v',
'n': 's', 'q': 'g', 'p': 't', 's': 'n','r': 'k', 'u': 'x', 't': 'p',
'w': 'h', 'v': 'o', 'y': 'z', 'x': 'u', 'z': 'y'}
def cipher(message):
word = list(message)
word = [v for x in word for k,v in d.iteritems() if x == k]
#word = [v for x in word for k,v in d.iteritems() if x == k else x for x in word]
return "".join(word)
print cipher("that tree is far away!")
This returns my string with the alpha characters correctly changed, but with no spaces and with no ! mark. From further research, that lead me to try the else statement I have in the list comprehension that is commented out in my code example, but that doesn't work.
Can I edit my syntax or can I not accomplish what I am trying to do using list comprehension?
To further clarify:
I am receiving this output: pwbppkjjcnlbkbhbz
I want this output: pwbp pkjj cn lbk bhbz!
Your current approach filters out all characters that are not in the dictionary viz. whitespace and the exclamation.
You could use the .get method of the dictionary instead to fetch replacements and return the original character when a replacement character does not exist in your mapping:
def decipher(message):
return "".join(d.get(x, x) for x in message)
print decipher("that tree is far away!")
#pwbp pkjj cn lbk bhbz!
Note that strings are iterable so word = list(message) is really not necessary and can be dropped.
On a another note, the name of the function probably reads better as cipher

Python dict issue when iterating [duplicate]

This question already has answers here:
Why is the order in dictionaries and sets arbitrary?
(5 answers)
Closed 6 years ago.
I've been searching everywhere for a problem that occurred in one of my codes, but didn't see any solution... It's been pretty annoying and that is why I'm asking you this question.
I'm using a simple dictionnary with keys and values, but the problem is when I want to print it at the end it has a strange shuffle where two letters are inverted, like for example "C":"W", "B":"X" instead of "B":"X", "C":"W". Here is my code (it will probably be clearer)
PS. I've first tried in the last few lines to replace the while structure by a for structure, with no improvement.
import random
m1 = ["ABCDEFGHIJKLMNOPQRSTUVWXYZ"]
l1 = ["ABCDEFGHIJKLMNOPQRSTUVWXYZ"]
class Separate:
#Used to separate objects in a list
def __init__(self, d):
self.d = d
self.d = "".join(self.d)
l = []
for elt in range(0, len(self.d)):
l.append(self.d[elt])
self.d = l
l1 = Separate(l1)
l1 = l1.d
m1 = Separate(m1)
m1 = m1.d
random.shuffle(m1)
key = {}
count = 0
while count < len(l1):
key[l1[count]] = m1[count]
count+=1
print(key)
This returns (for example) :
{
'A': 'G',
'C': 'A',
'B': 'Z',
'E': 'U',
'D': 'I',
'G': 'W',
'F': 'X',
'I': 'C',
'H': 'K',
'K': 'T',
'J': 'E',
'M': 'F',
'L': 'B',
'O': 'V',
'N': 'D',
'Q': 'M',
'P': 'L',
'S': 'S',
'R': 'J',
'U': 'Q',
'T': 'Y',
'W': 'H',
'V': 'R',
'Y': 'P',
'X': 'N',
'Z': 'O'
}
As mentioned in the comments, dicts don't have an order. If you need for your dict to track order, consider using an collections.OrderedDict
viz:
import collections
key = collections.OrderedDict()
You can do it using two string literals and zip:
m1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
l1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
key = {}
for m,l in zip(m1,l1):
key.update({m:l})
print(key)
~

How to keep "spaces" although dict contains it?

i am simply trying to read from a file encrypt and display it.
And I want to display the result word by word, but somehow spaces are removed (my dict also contains ' ':' ') and result text is displayed without spaces.
For example,
aa bb cc is what i read from file,
Current Output is ffggğğ, but i want it as ff gg ğğ
...please help...
monocrypt = {
'a': 'f',
'b': 'g',
'c': 'ğ',
'ç': 'h',
'd': 'ı',
'e': 'i',
'f': 'j',
'g': 'k',
'ğ': 'l',
'h': 'm',
'ı': 'n',
'i': 'o',
'j': 'ö',
'k': 'p',
'l': 'r',
'm': 's',
'n': 'ş',
'o': 't',
'ö': 'u',
'p': 'ü',
'r': 'v',
's': 'y',
'ş': 'z',
't': 'a',
'u': 'b',
'ü': 'c',
'v': 'ç',
'y': 'd',
'z': 'e',
' ': ' ',
}
inv_monocrypt = {}
for key, value in monocrypt.items():
inv_monocrypt[value] = key
f = open("C:\\Hobbit.txt","r")
print("Reading file...")
message = f.read()
crypt = ''.join(i for i in message if i.isalnum())
encrypted_message = []
for letter in crypt:
encrypted_message.append(monocrypt[letter.lower()])
print(''.join(encrypted_message))
You're dropping all the whitespace at this step
crypt = ''.join(i for i in message if i.isalnum())
So leave them all in there. Use dict.get with the default argument to preserve letters that aren't keys
crypt = f.read()
encrypted_message = []
for letter in crypt:
encrypted_message.append(monocrypt.get(letter.lower(), letter.lower()) )
If you really just want to preserve spaces (and not punctuation/other whitespace etc)
message = f.read()
crypt = ''.join(i for i in message if i.lower() in monocrypt)
encrypted_message = []
for letter in crypt:
encrypted_message.append(monocrypt[letter.lower()])
You can simplify a little like this
message = f.read().lower()
crypt = ''.join(i for i in message if i in monocrypt)
encrypted_message = [monocrypt[letter] for letter in crypt]
Not sure if it works as intended since I don't have hobbit.txt but I made a small rewrite to make the code a little simpler. It should also solve your problem.
monocrypt = {
'a': 'f',
'b': 'g',
'c': 'ğ',
'ç': 'h',
'd': 'ı',
'e': 'i',
'f': 'j',
'g': 'k',
'ğ': 'l',
'h': 'm',
'ı': 'n',
'i': 'o',
'j': 'ö',
'k': 'p',
'l': 'r',
'm': 's',
'n': 'ş',
'o': 't',
'ö': 'u',
'p': 'ü',
'r': 'v',
's': 'y',
'ş': 'z',
't': 'a',
'u': 'b',
'ü': 'c',
'v': 'ç',
'y': 'd',
'z': 'e',
' ': ' ',
}
with open("hobbit.txt") as hobbitfile:
file_text = hobbitfile.read()
crypted_message = ""
for char in file_text:
char = char.lower()
if char in monocrypt:
crypted_message += monocrypt[char]
else:
#I don't know if you want to add the other chars as well.
#Uncomment the next line if you do.
#crypted_message += str(char)
pass
print(crypted_message)
Check the docs :
http://docs.python.org/2/library/stdtypes.html#str.isalnum
isalnum drops your whitespaces.
use this if you want to preserve the space characters, everything else stays the same :
crypt = ''.join(i for i in message if i.isalnum() or i==' ')
If you want to preserve all whitespaces, do this :
crypt = ''.join(i for i in message if i.isalnum() or i.isspace())

Categories