0

I was wanting to convert a 576 bit binary number to hex so I wrote the following python script. While writing it was fun, i believe it to be massive, ugly, and most likely unnecessarily complicated. I was wondering if anyone new of a more efficient way to do this using some of the python built in. The issue I had using any that I could find was preserving the leading zeroes as it is absolutely critical. Below is the input and output i used to test and the code I wrote.

The input:

000011110111101011000101

The output:

0f7ac5

Code

file = open("binforhex.txt",'r')
stream = file.read()

num = []
byte = []
hexOut = []
n = 0

print stream

for x in stream:
    num.append(x)


while n < len(num):
    byte.append(int(num[n]))
    if n > 1:
        if (n + 1) % 4  == 0:
            if cmp([0, 0, 0, 0],byte) == 0 :
                hexOut.append('0')
            elif cmp([0, 0, 0, 1],byte) == 0 :
                hexOut.append('1')
            elif cmp([0, 0, 1, 0],byte) == 0 :
                hexOut.append('2')
            elif cmp([0, 0, 1, 1],byte) == 0 :
               hexOut.append('3')
            elif cmp([0, 1, 0, 0],byte) == 0:
                hexOut.append('4')
            elif cmp([0, 1, 0, 1],byte) == 0:
                hexOut.append('5')
            elif cmp([0, 1, 1, 0],byte) == 0:
                hexOut.append('6')
            elif cmp([0, 1, 1, 1],byte) == 0:
                hexOut.append('7')
            elif cmp([1, 0, 0, 0],byte) == 0:
                hexOut.append('8')
            elif cmp([1, 0, 0, 1],byte) == 0:
                hexOut.append('9')
            elif cmp([1, 0, 1, 0],byte) == 0:
                hexOut.append('a')
            elif cmp([1, 0, 1, 1],byte) == 0:
                hexOut.append('b')
            elif cmp([1, 1, 0, 0],byte) == 0:
                hexOut.append('c')
            elif cmp([1, 1, 0, 1],byte) == 0:
                hexOut.append('d')
            elif cmp([1, 1, 1, 0],byte) == 0:
                hexOut.append('e')
            elif cmp([1, 1, 1, 1],byte) == 0 :
                hexOut.append('f')
            byte.pop()
            byte.pop()
            byte.pop()
            byte.pop()
    n += 1
print ''.join(hexOut)
Tom
  • 312
  • 5
  • 17

2 Answers2

3

The total number of hex digits you want, starting from binary string b, is

hd = (len(b) + 3) // 4

So...:

x = '%.*x' % (hd, int('0b'+b, 0))

should give you what you want (with a '0x' prefix that you can easily slice away of course, just use x[2:]).

Added: the format string '%.*x' means "format as hexadecimal to a length as per supplied parameter, with leading zeros". The "supplied parameter" here is hd, the total number of hex digits we require.

The simple, key concept is to think in terms of total number of digits (binary on input, hex on output) rather than the "number of leading zeros" in each case -- the latter will just fall into place. E.g, if the input binary string has 576 bits, no matter how many of them are "leading zeros", you want the output hex string to have 576 // 4, i.e, 144, hex digits, so that's what hd will be set to -- and that's how many digits you'll get by this formatting (as many of them will be "leading zeros" as needed -- no more, no less).

Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
  • that works flawlessly, but im not sure excactly how it does it. Any chance you want to clarify the second part? – Tom Jan 12 '15 at 05:28
  • Done -- added verbose explanation, I hope it helps! – Alex Martelli Jan 12 '15 at 05:36
  • It most definitely did. Thank you. – Tom Jan 12 '15 at 05:38
  • 2
    @Tom: you could also use `format()`: `'{:0{}x}'.format(int(b, 2), hd)` – jfs Jan 12 '15 at 10:18
  • @J.F.Sebastian, you're right, and it would be more elegant -- I'm a "old hand" so I slip naturally into `%`-formatting, but in today's Python `.format` is much better (my resolution is to use the latter exclusively in the next edition of the Nutshell!-). – Alex Martelli Jan 12 '15 at 14:43
  • In general, `format()` avoids `%tuple`, `%dict`, `bytestring%unicode` gotchas. To format a number, both variants work well. `%` or [`hex()[:2].zfill()` might be faster](http://stackoverflow.com/a/12162856/4279) – jfs Jan 12 '15 at 15:15
0

Did you know there's a hex() builtin? It converts any number (including binary numbers, starting with 0b) to a hex string:

>>> hex(0b000011110111101011000101)
'0xf7ac5'
MattDMo
  • 100,794
  • 21
  • 241
  • 231
  • I tried that, but notice the loss of the leading zero. The 576 bit number I intend to use this for will have a large varying number of leading zeroes i must preserve. – Tom Jan 12 '15 at 04:45
  • 1
    @Tom, well, you can use this to return the hex value, strip off the leading `0x`, check the length of the result, and if not long enough prepend 1 or more zeroes using `str.format()`. Easy enough. – MattDMo Jan 12 '15 at 04:50