Nenunathel
Nenunathel

Reputation: 405

How to decode a binary code into text?

Just as a project out of fun, I wanted to build a simple binary encoder with Python. After that worked very well, I moved on to upgrade it as an encoder and a decoder... and suddenly, it doesn't seem to work (only the second option, the first option still works fine).

The error I get when I want to decode for example '0100 0001', which stands for "A", is as follows:

Your message to decode: 0100 0010
KeyError                                  Traceback (most recent call last)
C:\Users\marco\AppData\Local\Enthought\Canopy32\App\appdata\canopy-1.4.0.1938.win-x86\lib\site-packages\IPython\utils\py3compat.pyc in execfile(fname, glob, loc)
    195             else:
    196                 filename = fname
--> 197             exec compile(scripttext, filename, 'exec') in glob, loc
    198     else:
    199         def execfile(fname, *where):

C:\Users\marco\Dropbox\1_TUDelft\4Q\AE1205 Python\my own codes\binary encoder.py in <module>()
     41     messageDecode = raw_input("Your message to decode: ")
     42     for character in messageDecode:
---> 43         print inverseBINARY[character],

KeyError: '0' 

My suspicion is that it is the last command, the print command, however I do not know how to correct it... Any suggestions?

Here is the code:

BINARY = {"A":"0100 0001",
"B":"0100 0010",
"C":"0100 0011",
"D":"0100 0100",
"E":"0100 0101",
"F":"0100 0110",
"G":"0100 0111",
"H":"0100 1000",
"I":"0100 1001",
"J":"0100 1010",
"K":"0100 1011",
"L":"0100 1100",
"M":"0100 1101",
"N":"0100 1110",
"O":"0100 1111",
"P":"0101 0000",
"Q":"0101 0001",
"R":"0101 0010",
"S":"0101 0011",
"T":"0101 0100",
"U":"0101 0101",
"V":"0101 0110",
"W":"0101 0111",
"X":"0101 1000",
"Y":"0101 1001",
"Z":"0101 1010",
" ":"0100 0000",
".":"0010 1110",
",":"0010 1100",
"?":"0011 1111"}

inverseBINARY = {v:k for k,v in BINARY.items()}

question = input("Do you wish to encode(press 1) or decode(press 2) into/from binary?")

if question == 1:
    messageEncode = raw_input("Your message to encode: ")
    for character in messageEncode:
        print BINARY[character.upper()],

if question == 2:
    messageDecode = raw_input("Your message to decode: ")
    for character in messageDecode:
        print inverseBINARY[character],    

Upvotes: 1

Views: 9360

Answers (3)

alvas
alvas

Reputation: 122142

To convert ascii to binary:

>>> format(ord('A'), 'b')
'1000001'

To convert binary to ascii:

>>> chr(int('1000001',2))
'A'

Here's a more compact version of your code:

question = raw_input("Your message to encode/decode: ")

try:
    question = int(question, 2) # Checks if inptu is binary.
    print 'Decoding...'
    print chr(question)
except:
    print 'Encoding...'
    print "".join([format(ord(i), 'b') for i in question])

[test]:

alvas@ubi:~$ python test.py 
Your message to encode/decode: 1000001
Decoding...
A
alvas@ubi:~$ python test.py 
Your message to encode/decode: A
Encoding...
1000001

Upvotes: -1

Martijn Pieters
Martijn Pieters

Reputation: 1123250

You are looping over the individual characters of the input message, but you need to instead look for groups of 9 characters (2 times 4 binary digits and the space). Your mapping has keys like '0100 1001', not '0' and '1' and ' '

The simplest approach (albeit a bit brittle) would be to loop over indices in steps of 10 characters (1 extra for the space between the characters), then grab 9 characters:

for i in xrange(0, len(messageDecode), 10):
    group = messageDecode[i:i + 9]
    print inverseBINARY[group],    

The xrange() object produces integers 10 apart; so 0, 10, 20, etc. The messageDecode string is then sliced to grab 9 characters starting at that index, so messageDecode[0:9] and messageDecode[10:19], messageDecode[20:29], etc.

A more robust approach would be to remove all spaces and grab blocks every 8 characters; that'd leave room for extra spaces in between, but you do have to re-insert that space to match your keys:

messageDecode = messageDecode.replace(' ', '')
for i in xrange(0, len(messageDecode), 8):
    group = messageDecode[i:i + 4] + ' ' + messageDecode[i + 4:i + 8]
    print inverseBINARY[group],    

or you could perhaps not include the spaces in your inverseBINARY mapping here:

inverseBINARY = {v.replace(' ', ''): k for k, v in BINARY.items()}

and then simply slice every 8 characters:

messageDecode = messageDecode.replace(' ', '')
for i in xrange(0, len(messageDecode), 8):
    group = messageDecode[i:i + 8]
    print inverseBINARY[group], 

Upvotes: 3

markcial
markcial

Reputation: 9333

if you want to decode binary why not use native functions as the binary number and chr ?

>>> print chr(0b01000010)
B

EDIT

Ok then, this is how i would solve that:

from string import letters, punctuation
encode_data = {letter:bin(ord(letter)) for letter in letters+punctuation+' '}
decode_data = {bin(ord(letter)):letter for letter in letters+punctuation+' '}

def encode(message):
    return [encode_data[letter] for letter in message]

def decode(table):
    return [decode_data[item] for item in table]

encoded = encode('hello there')
print decode(encoded) # ['h', 'e', 'l', 'l', 'o', ' ', 't', 'h', 'e', 'r', 'e']

Upvotes: -1

Related Questions