Python以大十六进制数获取特定字节

时间:2018-08-03 18:04:06

标签: python bit-manipulation byte

假设我有一个很大的十六进制数字0x1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF

我想轻松地从这个十六进制数中获取10-20字节,我该怎么做呢?我知道我可以将数据右移10 * 8次,但剩余的十六进制数字仍然是有效字节。

2 个答案:

答案 0 :(得分:0)

最简单的方法是使用字符串切片。由于最低字节在最右边,最高字节在左边,因此我们可以利用负索引。

def sub_bytes(i, start=0, end=0):
    i_str = hex(i)[2:]  # skip 0x part
    i_sub = i_str[-end * 2: len(i_str) - start * 2]  # get the bytes we need
    return int(i_sub or '0', 16)  # convert to back int

len(i_str)在这里,用于更好的start = 0处理

让我们尝试您的价值

In [2]: value = 0x1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF

In [3]: sub_bytes(value, 0, 3)
Out[3]: 11259375

In [4]: hex(sub_bytes(value, 0, 3))
Out[4]: '0xabcdef'

In [6]: hex(sub_bytes(value, 10, 20))
Out[6]: '0x90abcdef1234567890ab'

In [7]: hex(sub_bytes(value, 45))
Out[7]: '0x123456'

如果请求的切片为空或超出范围,我在这里返回0x0,但是如果愿意,您可以提高IndexError

更新

在Python 3.2+中,int上定义了to_bytesfrom_bytes,在这种情况下更高效,更方便

import math

def slice_bytes(value, a=None, b=None, byteorder='little'):
    size = math.ceil(value.bit_length() / 8)
    value_bytes = value.to_bytes(size, byteorder)
    return int.from_bytes(value_bytes[a: b], byteorder)

在对具有288998字节的数字7 ** 7 ** 7进行了性能测试之后,我发现slice_bytes比Karl的直接方法要快。 sub_bytes显然要慢一些。

答案 1 :(得分:0)

我觉得位掩码方法不是弄乱字符串和子字符串,而是一种更直接的方法来获取所需的位。在您的评论中,您提到位掩码非常大,这是事实,但这对程序而言不是问题。

我有一个示例函数,可以根据要从数据中获取多少个字节为您制作掩码。然后,您只需AND使用具有右移值的掩码即可获得所需的值。

假设您要从字节索引2开始获取4个字节的数据。

def get_bytes(value, start, amount):  
    shifted_value = value >> (start * 8) # Multiply by 8 for how much to right shift
    mask = make_mask(amount) 
    return shifted_value & mask

def make_mask(byte_amount):
    if byte_amount > 0:
        bin_string = '1' * (byte_amount * 8)  # Create binary string mask
    else:
        bin_string = '0'  # Make result 0
    return int(bin_string, 2)  # Return integer representation

value = 0x1234567890ABCDEF1234567890ABCDEF
result = get_bytes(value, 2, 4)

结果最终为十进制整数1450741931,转换为十六进制的0x567890ab