How to convert hex strings to binary ascii strings in python (incl. 8bit space)

As i come across this again and again:

How do you turn a hex string like "c3a4c3b6c3bc" into a nice binary string like this: "11000011 10100100 11000011 10110110 11000011 10111100"?

The solution is based on the Python 2.6 new string formatting:

>>> "{0:8b}".format(int("c3",16))
'11000011'

Which can be decomposed into 4 bit for each hex char like this: (notice the 04b, which means 0-padded 4chars long binary string):

>>> "{0:04b}".format(int("c",16)) + "{0:04b}".format(int("3",16))
'11000011'

OK, now we could easily do this for all hex chars "".join(["{0:04b}".format(int(c,16)) for c in "c3a4c3b6"]) and done, but usually we want a blank every 8 bits from the right to left… And looping from the right pairwise is a bit more complicated… Oh and what if the number of bits is uneven?
So the solution looks like this:

>>> binary = lambda x: " ".join(reversed( [i+j for i,j in zip( *[ ["{0:04b}".format(int(c,16)) for c in reversed("0"+x)][n::2] for n in [1,0] ] ) ] ))
>>> binary("c3a4c3b6c3bc")
'11000011 10100100 11000011 10110110 11000011 10111100'

It takes the hex string x, first of all concatenates a "0" to the left (for the uneven case), then reverses the string, converts every char into a 4-bit binary string, then collects all uneven indices of this list, zips them to all even indices, for each in the pairs-list concatenates them to 8-bit binary strings, reverses again and joins them together with a ” ” in between. In case of an even number the added 0 falls out, because there’s no one to zip with, if uneven it zips with the first hex-char.

Yupp, I like 1liners 😉

Update: Btw, it’s very easy to combine this with binascii.hexlify to get the binary representation of some byte-string:

>>> import binascii
>>> binascii.hexlify('jörn')
'6ac3b6726e'
>>> binary(binascii.hexlify('jörn'))
'01101010 11000011 10110110 01110010 01101110'

7 thoughts on “How to convert hex strings to binary ascii strings in python (incl. 8bit space)

  1. Jean-sébastien

    Thann you vert much, a simply powerful script working as well. Perfect 🙂

    Reply
  2. Michael Caplan

    I’m having an issue implementing this (and please forgive me for being such a newbie)…
    I have a file with 300 some odd lines such as:
    7E405100C6710110CCFE1F003901000000000000037E

    I’ve integrated your bit as follows:

    pre_file = ‘parser.log’
    stripped_file = ‘stripped.txt’
    binary_file = ‘binary.txt’
    binary = lambda x: ” “.join(reversed( [i+j for i,j in zip( *[ [“{0:04b}”.format(int(c,16)) for c in reversed(“0″+x)][n::2] for n in [1,0] ] ) ] ))

    open(‘stripped_file’, “w”).write(open(pre_file).read().replace(” “,””) .strip())
    open(‘binary_file’, “w”).write(open(stripped_file).read() .binary(x))

    When I run it – I get the following error:
    open(‘binary_file’, “w”).write(open(stripped_file).read() .binary(x))
    AttributeError: ‘str’ object has no attribute ‘binary’

    I’m at a loss and appreciate your assistance in advance!

    Reply
    1. joern Post author

      hmm, your code looks a bit confused, you’re trying to use .binary(x) on the result of .read(), the latter is a string and we didn’t register the binary function as a string method…

      i have to guess a lot: you probably want to turn that around and also iterate over your opened file and keep newlines:

      with open(binary_file, 'w') as output_file:
          with open(stripped_file) as input_file:
              for line in input_file:
                  output_file.write(binary(line.strip()) + '\n')
      
      Reply
      1. Michael Caplan

        Yeah – I obscured a bit too much. Basically, I have a file with 300+ lines like:

        7E405100CB71FA1FCCFE1F003901000000000000F67E
        7E405100C6710110CCFE1F003901000000000000037E
        7E405100C67105108CFE1F0039010000000000003F7E
        7E405100C47108108CFE1F0039010000000000003E7E
        7E405100C27106105CFE1F003901000000000000727E
        7E405100BF7105105CFE1F003901000000000000767E

        I need to turn these HEX bytes into a binary bitmap output to another file like:

        0111 1110 0100 0000 0101 0001 0000 0000 1100 1011 0111 0001…..
        0111 1110 0100 0000 0101 0001 0000 0000 1100 0110 0111 00011….

        Is this enough information? Will the fix you suggested above create the output I need?

        Reply
  3. Lawrence

    Hi Joern,

    Could you help me to understand why your code can pick out even and odd elements in a list? Specifically, how does [n::2] for n in [1,0] work? I try it out on interpreter and get an error. But, if I combine it with a

    [[1,2,3,4,5][n::2] for n in [1, 0] ]
    [[2, 4], [1, 3, 5]]

    [ [n::2] for n in [1, 0] ]
    File "", line 1
    [ [n::2] for n in [1, 0] ]
    ^
    SyntaxError: invalid syntax

    Thank you,

    Lawrence

    Reply
    1. joern Post author

      I think you’re confused by [] being used for lists (e.g., [1,2,3]) and slices (e.g., something[start:stop:step]). The slightly sloppy takeaway here is: slices do not exist without something in front of them.

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

 

This site uses Akismet to reduce spam. Learn how your comment data is processed.