Related
Suppose I have a list in the form;
lst = ["5kxn"] # 1 string only for example
5k denotes 5000 and xn denotes n times, the processed list should be;
[5*1e3 for i in range(n)] # float values
#Not this literally but a list of n 5000's.
I am aware I can do this using non re methods but it could be bug prone, and my re skills are not good enough to come up with a method to pull off this conversion
Here is a dictionary of multipliers:
replace_dict = {'a': '1e-18', 'f': '1e-15', 'p': '1e-12',
'n': '1e-9', 'u': '1e-6', 'm': '1e-3',
'c': '1e-2', 'd': '1e-1', 'da': '1e1',
'h': '1e2', 'k': '1e3', 'M': '1e6',
'G': '1e9', 'T': '1e12', "P": '1e15',
'E': '1e18'}
Desired output is a list. For example ["2kx1","3kx2","4k"] will be [2000.0,3000.0,3000.0,4000.0]
import re
replace_dict = {'a': '1e-18', 'f': '1e-15', 'p': '1e-12',
'n': '1e-9', 'u': '1e-6', 'm': '1e-3',
'c': '1e-2', 'd': '1e-1', 'da': '1e1',
'h': '1e2', 'k': '1e3', 'M': '1e6',
'G': '1e9', 'T': '1e12', "P": '1e15',
'E': '1e18'}
def str_to_list(list_str):
regex = re.compile(r"([0-9]+)([^x]+)(x[0-9]+)?")
list_numbers = []
for string in list_str:
parsed = re.findall(regex, string)[0]
n = 1 if parsed[2] == '' else int(parsed[2].replace('x', ''))
list_numbers += [float(parsed[0]) * eval(replace_dict[parsed[1]])] * n
return list_numbers
result = str_to_list(["2kx1","3kx2","4k"])
print(result) # [2000.0, 3000.0, 3000.0, 4000.0]
A bit of explanation:
([0-9]+): captures what comes before the unit prefix, e.g. k.
([^x]+): captures the unit prefix (anything that is not an "x"). This could be refined so it only accepts the letters defined in replace_dict. The + is needed because of the 'da' prefix.
(x[0-9]+)?: captures the multiplier, e.g. x2, if exists.
The method re.findall returns a list, in these case containing a tuple with the groups captured by the regex, e.g.: [('22', 'k', 'x2')] for "22kx2". We take [0] to work directly with the tuple.
If the "xn" is missing, re.findall will return an empty string for the group (x[0-9]+)? since there's not any match, e.g.: [('2', 'k', '')] for "2k". That's why n is 1 if that string is empty, else we discard the x (replacing it with an empty string, i.e. replace('x', '')), so we only take the number, e.g. 2 in "x2".
Finally, we concatenate the resulting list to list_numbers, e.g. list_numbers += [2 * eval("1e3")] * 2 in case of "2kx2".
Hope that was clear enough :)
Here is a regex based approach which ultimately uses the eval() function to evaluate a string expression to generate a list:
def get_list(inp):
replace_dict = {'a': '1e-18', 'f': '1e-15', 'p': '1e-12',
'n': '1e-9', 'u': '1e-6', 'm': '1e-3',
'c': '1e-2', 'd': '1e-1', 'da': '1e1',
'h': '1e2', 'k': '1e3', 'M': '1e6',
'G': '1e9', 'T': '1e12', 'P': '1e15',
'E': '1e18'}
parts = re.findall(r'^(\d+)(\w+)x(\w+)$', inp)
expr = "[" + parts[0][0] + "*" + replace_dict[parts[0][1]] + " for i in range(" + parts[0][2] + ")]"
return expr
expr = get_list("5kxn")
print(expr) # [5*1e3 for i in range(n)]
n = 5
lst = eval(expr)
print(lst) # [5000.0, 5000.0, 5000.0, 5000.0, 5000.0]
I started to translate Morse code to English and there is an issue. Here is my code:
morse_dict = {
'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': '--..',
}
def morse_decrypt(message):
m1 = message.split()
new_str = []
letter = ''
for i,n in morse_dict.items():
if n in m1:
letter = str(i)
new_str.append(letter)
return ''.join(new_str)
print(morse_decrypt('... --- ...'))
>>>os
But when I try to use function it prints each character one time. I don't know what the problem. What I am doing wrong?
Your morse_dict translates alphabetical letters into Morse code letters. But you want the reverse since you're trying to decrypt rather than encrypt. Either rewrite your dictionary or use
morse_to_alpha = dict(map(reversed, morse_dict.items()))
to flip the key-value pairs.
Once you've done that, then you can look up each message chunk in the translation dictionary (rather than the other way around):
def morse_decrypt(message):
morse_to_alpha = dict(map(reversed, morse_dict.items()))
return "".join(map(morse_to_alpha.get, message.split()))
This still breaks encapsulation. morse_to_alpha should be made into a parameter so you're not accessing global state, and it's wasteful to flip the dict for every translation. I'll leave these adjustments for you to handle.
It's also unclear how to handle errors; this raises a (not particularly clearly named) exception if the Morse code is invalid.
You have a dictionary with the Key as the letter and the code as the value.
Python dictionaries are lookup by key not value(Unfortunately), BUT there is a way around this as you probably found.
Pull the dictionary into items for letter and code like you were doing, BUT put the code to lookup in the first FOR loop. :)
def morse_decrypt(message):
global morse_dict
msgList = message.split(" ")
msgEnglish = ""
for codeLookup in msgList:
for letter, code in morse_dict.items():
if(code == codeLookup):
msgEnglish += letter
return msgEnglish
print(morse_decrypt('... --- ...'))
references:
Get key by value in dictionary
https://www.w3schools.com/python/python_dictionaries.asp
https://imgur.com/a/AVsyR
My code. No errors show up on the editor.
def word_to_code(word):
#TODO1
myTranslatedWord = ""
for a in range(0, len(word)):
for b in range(0, len(code)):
if(word[a] == code[b]):
myTranslatedWord += code[b]
print(myTranslatedWord)
return(myTranslatedWord)
code = {'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((word_to_code("PAPI"))
This is for a class where I'm trying to independently problem solve an objective. For some reason though my code is not working.
You have one too many parentheses in the last line. It should be
print(word_to_code("PAPI"))
In the future, copy the actual text of the error into the question instead of as a picture.
Note that there's also a fairly large problem with how you do the translation. Remember what dictionaries are good for - you should be able to write that function with only a single loop.
I have a dictonairy I want to compare to my string, for the each ke in the dictoniary which matches that in the string I wish to convert the string character to that of the dictoniary
I want to compare my dictionary to my string character by character and when they match replace the strings character with the value of the dictionary's match e.g. if A is in the string it will match to A in the dictionary and be replaced with T which is written to the file line2_u_rev_comp. However the error KeyError: '\n' occurs instead. What is this signaling and how can it be removed?
REV_COMP = {
'A': 'T',
'T': 'A',
'C': 'G',
'G': 'C',
'N': 'N',
'U': 'A'
}
tbl = REV_COMP
line2_u_rev_comp = [tbl[k] for k in line2_u_rev[::-1]]
''.join(line2_u_rev_comp)
'\n' means new line, and you can get rid of it (and other extraneous whitespace) using str.strip, e.g.:
line2_u_rev_comp = [tbl[k] for k in line2_u_rev.strip()[::-1]]
line2_u_rev_comp = [tbl.get(k,k) ... ]
this will either get it from the dictionary or return itself
The problem is the tbl[k] but you don't check if the key exists in the dict, if not you need to return k it self.
you also need to reverse again the list since your for statement is reversed.
Try this code:
line2_u_rev = "MY TEST IS THIS"
REV_COMP = {
'A': 'T',
'T': 'A',
'C': 'G',
'G': 'C',
'N': 'N',
'U': 'A'
}
tbl = REV_COMP
line2_u_rev_comp = [tbl[k] if k in tbl else k for k in line2_u_rev[::-1]][::-1]
print ''.join(line2_u_rev_comp)
Output:
MY AESA IS AHIS
Objective: Convert binary to string
Example: 0111010001100101011100110111010001100011011011110110010001100101 -> testCode (without space)
I use a dictionary and my function, i search a better way and more efficient
from textwrap import wrap
DICO = {'\x00': '00', '\x04': '0100', '\x08': '01000', '\x0c': '01100',
'\x10': '010000', '\x14': '010100', '\x18': '011000', '\x1c': '011100',
' ': '0100000', '$': '0100100', '(': '0101000', ',': '0101100', '0': '0110000',
'4': '0110100', '8': '0111000', '<': '0111100', '#': '01000000',
'D': '01000100', 'H': '01001000', 'L': '01001100', 'P': '01010000',
'T': '01010100', 'X': '01011000', '\\': '01011100', '`': '01100000',
'd': '01100100', 'h': '01101000', 'l': '01101100', 'p': '01110000',
't': '01110100', 'x': '01111000', '|': '01111100', '\x03': '011',
'\x07': '0111', '\x0b': '01011', '\x0f': '01111', '\x13': '010011',
'\x17': '010111', '\x1b': '011011', '\x1f': '011111', '#': '0100011',
"'": '0100111', '+': '0101011', '/': '0101111', '3': '0110011', '7': '0110111',
';': '0111011', '?': '0111111', 'C': '01000011', 'G': '01000111',
'K': '01001011', 'O': '01001111', 'S': '01010011', 'W': '01010111',
'[': '01011011', '_': '01011111', 'c': '01100011', 'g': '01100111',
'k': '01101011', 'o': '01101111', 's': '01110011', 'w': '01110111',
'{': '01111011', '\x7f': '01111111', '\x02': '010', '\x06': '0110',
'\n': '01010', '\x0e': '01110', '\x12': '010010', '\x16': '010110',
'\x1a': '011010', '\x1e': '011110', '"': '0100010', '&': '0100110',
'*': '0101010', '.': '0101110', '2': '0110010', '6': '0110110', ':': '0111010',
'>': '0111110', 'B': '01000010', 'F': '01000110', 'J': '01001010',
'N': '01001110', 'R': '01010010', 'V': '01010110', 'Z': '01011010',
'^': '01011110', 'b': '01100010', 'f': '01100110', 'j': '01101010',
'n': '01101110', 'r': '01110010', 'v': '01110110', 'z': '01111010',
'~': '01111110', '\x01': '01', '\x05': '0101', '\t': '01001', '\r': '01101',
'\x11': '010001', '\x15': '010101', '\x19': '011001', '\x1d': '011101',
'!': '0100001', '%': '0100101', ')': '0101001', '-': '0101101',
'1': '0110001', '5': '0110101', '9': '0111001', '=': '0111101',
'A': '01000001', 'E': '01000101', 'I': '01001001', 'M': '01001101',
'Q': '01010001', 'U': '01010101', 'Y': '01011001', ']': '01011101',
'a': '01100001', 'e': '01100101', 'i': '01101001', 'm': '01101101',
'q': '01110001', 'u': '01110101', 'y': '01111001', '}': '01111101'}
def decrypt(binary):
"""Function to convert binary into string"""
binary = wrap(binary, 8)
ch = ''
for b in binary:
for i, j in DICO.items():
if j == b:
ch += i
return ch
thank by advance,
''.join([ chr(int(p, 2)) for p in wrap(binstr, 8) ])
What this does: wrap first splits your string up into chunks of 8. Then, I iterate through each one, and convert it to an integer (base 2). Each of those converted integer now get covered to a character with chr. Finally I wrap it all up with a ''.join to smash it all together.
A bit more of a breakdown of each step of the chr(int(p, 2)):
>>> int('01101010', 2)
106
>>> chr(106)
'j'
To make it fit into your pattern above:
def decrypt(binary):
"""Function to convert binary into string"""
binary = wrap(binary, 8)
ch = ''
for b in binary:
ch += chr(int(b, 2))
return ch
or
def decrypt(binary):
"""Function to convert binary into string"""
return ''.join([ chr(int(p, 2)) for p in wrap(binary, 8) ])
This is definitely faster since it is just doing the math in place, not iterating through the dictionary over and over. Plus, it is more readable.
If execution speed it the most important for you, why not invert the roles of keys and values in your dict?! (If you also need the current dict, you could created an inverted version like this {v:k for k, v in DICO.items()})
Now, you find directly the searched translation by key instead of looping through the whole dict.
Your new function would look like this:
def decrypt2(binary):
"""Function to convert binary into string"""
binary = wrap(binary, 8)
ch = ''
for b in binary:
if b in DICO_INVERTED:
ch += DICO_INVERTED[b]
return ch
Depending on the size of your binary string, you could gain some time by changing the way you construct your output-string (see Efficient String Concatenation in Python or performance tips - string concatenation). Using join seems promising. I would give it a try: ''.join(DICO_INVERTED.get(b, '') for b in binary)
did you try
def decrypt(binary):
"""Function to convert binary into string"""
return ''.join(( chr(int(p, 2)) for p in grouper(8,binary,'') ))
where grouper is taken from here http://docs.python.org/library/itertools.html#recipes
or
def decrypt2(binary):
"""Function to convert binary into string"""
return ''.join(( DICO_INVERTED[p] for p in grouper(8,binary,'') ))
that avoids to create temporary list
EDIT
as I was choisen to be the "right" answer I have to confess that I used the other answers. The point is here not to use generator list but generator expression and iterators