felix001
felix001

Reputation: 16691

Coverting Hex array to Decimal in Python

I have a Hex Array which looks like :

31 31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

When converting this to binary this looks like : 0011000100110001

Each bit is a flag that relates to a number within the array. In this case this binary number would equal 2,3,7,10,11,15.

I'm not sure if there is a name for this notation, but is there any easy method to convert the hex about to get a list of decimal numbers as shown above.

So,

Each 0x31 equates to a byte or 8 bits.

Each 0x31 converts to 00110001.

The way that this binary is then supposed to be interpretted is.

0 1 2 3 4 5 6 7 8 9 10
0 0 1 1 0 0 0 1 ......

Here you can see I get the decimal values 2,3,7 from the 0x31.

Hope this makes sense. Any help would be greatly appreciated.

Upvotes: 0

Views: 5968

Answers (6)

Oleh Prypin
Oleh Prypin

Reputation: 34116

So we have the hex numbers in a space-separated string.

s = '31 31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'

Now we split the string, convert each byte from hex string to int (int('31', 16) == 49), then convert it to binary string (bin(49) == '0b110001'), then take away the '0b' with [2:], add zeroes at the beginning so the sequence exactly 8 long ('110001'.zfill(8) == '00110001'). Then we join all the bit strings together in one string.

s = ''.join(bin(int(b, 16))[2:].zfill(8) for b in s.split())
# Now `s` is '0011000100110001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
  • An alternative to the above line, that works in Python 2.5:
    trans = {'0':'0000','1':'0001','2':'0010','3':'0011','4':'0100','5':'0101','6':'0110','7':'0111','8':'1000','9':'1001','a':'1010','b':'1011','c':'1100','d':'1101','e':'1110','f':'1111',' ':''}
    s = ''.join(trans[c] for c in s.lower())

Then we enumerate the bits, so every bit (b) will have a corresponding position (i), just as you described. We use a list comprehension and include only those positions at which the symbol is '1'.

r = [i for i, b in enumerate(s) if b=='1']
# Now `r` is [2, 3, 7, 10, 11, 15]

Upvotes: 5

mitch
mitch

Reputation: 1900

Transform everything in a big bit string and then enumerate it. Mostly similar to blaxpirit's answer but it does not use the [:2] hack.

array = [0x31, 0x31, 0, 0, 0]
[i for i, x in enumerate("".join(format(a, "08b") for a in array)) if x == '1']

Results in

[2, 3, 7, 10, 11, 15]

Upvotes: 6

jfs
jfs

Reputation: 414179

Using a precomputed positions list:

arr = [0x31, 0x31, 0, 0, 0]
print [(8*byte_ind + i) for byte_ind, b in enumerate(arr) for i in positions[b]]
# -> [2, 3, 7, 10, 11, 15]

Where positions maps all (256) bytes to corresponding positions:

>>> def num2pos(n):
...     return [i for i, b in enumerate(format(n, '08b')) if b == '1']
... 
>>> positions = map(num2pos, range(0x100))
>>> positions[0x31]
[2, 3, 7]

If your array is actually a hex string then you could convert it to a bytearray:

>>> import binascii
>>> arr = bytearray(binascii.unhexlify(s.replace(' ', '')))
>>> arr
bytearray(b'11\x00\x00\x00\x00\x00...\x00')

Upvotes: 1

Josiah
Josiah

Reputation: 3326

Alright, so, first things first, you need to convert that hex array into integer, then to binary. This is pretty simple in python:

myBin = bin(int("".join(hexArray),16))[2:].zfill(len(hexArray)*8) #We slice to get rid of the "0b" prepended by the bin function. zfill puts in leading zeros so we don't miss anything

Following that, we can do some cool enumeration and list comprehension in order to get the numbers we need:

myInts = [off for x, off in enumerate(myBin) if x == "1"]

So, assuming you already have your hex in an array, this will give you the answer you are looking for.

Upvotes: 2

Andrew Clark
Andrew Clark

Reputation: 208465

I think the following does what you are looking for:

def to_int_list(hex_array):
    hex_str = ''.join(hex_array)
    value = int(hex_str, 16)
    i = 4*len(hex_str) - 1
    result = []
    while value:
        if value & 1:
            result.append(i)
        value = value >> 1
        i -= 1
    return result[::-1]


>>> to_int_list(['31', '31', '00', '00', '00', '00'])
[2, 3, 7, 10, 11, 15]

Upvotes: 0

user1277476
user1277476

Reputation: 2909

>>> print int('31', 16)
49

From there, you can use a list comprehension or generator expression to do the multiple values.

Upvotes: 0

Related Questions