简体   繁体   中英

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.

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]

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',' ':''} \ns = ''.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]

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.

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')
>>> print int('31', 16)
49

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

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]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM