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'