Fred
Fred

Reputation: 1021

binary to string, better than a dictionary?

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,

Upvotes: 6

Views: 1552

Answers (3)

Xavier Combelle
Xavier Combelle

Reputation: 11235

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

Upvotes: 2

gecco
gecco

Reputation: 18860

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)

Upvotes: 3

Donald Miner
Donald Miner

Reputation: 39913

''.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.

Upvotes: 14

Related Questions