Reputation: 16691
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
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'
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
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
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
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
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
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