如何在Python中将2-5字节长的字节数组中的位移?

10
我正在尝试从一个字节对象中提取数据。例如: 从b'\x93\x4c\x00'中,我的整数隐藏在第8位到第21位的二进制位。 我试图使用bytes >> 3,但当有多个字节时这不可能。 我还尝试使用struct来解决这个问题,但字节对象必须具有特定的长度。
如何将位向右移动?

在Perl中,您可以使用my $i = ( unpack('N', substr("\x00\x00".$s, -4)) >> 8) & 0x1FFF; - ikegami
请注意,位从右向左计数,从0开始;第8位是\x4c字节的最后一位,第16到21位是第一个字节最右边的5位。您的移位3意味着您正在从左到右计算位;也许您正在寻找不同于传统的一组位? - Martijn Pieters
4个回答

10

不要使用bytes来表示整数值;如果你需要位(bits),请转换为int

value = int.from_bytes(your_bytes_value, byteorder='big')
bits_21_to_8 = (value & 0x1fffff) >> 8

其中0x1fffff掩码也可以用以下方式计算:

mask = 2 ** 21 - 1

演示:

>>> your_bytes_value = b'\x93\x4c\x00'
>>> value = int.from_bytes(your_bytes_value, byteorder='big')
>>> (value & 0x1fffff) >> 8
4940

您可以使用int.to_bytes()方法将其转换回字节:

>>> ((value & 0x1fffff) >> 8).to_bytes(2, byteorder='big')
b'\x13L'

1
对于通过谷歌搜索到这里的人:请注意,此解决方案仅适用于使用Python 3的情况。在Python 2中,“int”类没有“from_bytes”方法。 - larsks
1
@larsks: 是的,该问题特别标记了 [tag:python-3.x] 标签。 :-) - Martijn Pieters
要获取8-21位,您可以丢弃前8位并从剩下的13位中取出:(value >> 8) & 0b1_1111_1111_1111。要从偏移量开始获取x中的n位:get_bits = lambda x, n, offset=0: (x >> offset) & ~-(1 << n) - jfs

4

如果您有一个字节字符串并且想要去除最右边的八个位(即一个字节),您可以直接从字节字符串中简单地去除它:

>>> b'\x93\x4c\x00'[:-1]
b'\x93L'

如果您想将其转换为整数,则可以使用Python的struct对其进行解包。正如您正确指出的那样,您需要一个固定的大小来使用结构体,因此您只需填充字节字符串以添加所需数量的零即可:
>>> data = b'\x93\x4c\x00'
>>> data[:-1]
b'\x93L'
>>> data[:-1].rjust(4, b'\x00')
b'\x00\x00\x93L'
>>> struct.unpack('>L', data[:-1].rjust(4, b'\x00'))[0]
37708

当然,你也可以先将其转换,然后从结果整数中移除8位。
>>> struct.unpack('>Q', data.rjust(8, b'\x00'))[0] >> 8
37708

如果您想确保实际解释的位数不超过13位(第8到21位),当然需要应用位掩码0x1FFF

>>> 37708 & 0x1FFF
4940

如果您需要大端序,只需分别使用<L<Q即可。

如果你真的按照从左到右计算比特(这很不寻常,但可以接受),那么你也可以使用这种填充技术:

>>> struct.unpack('>Q', data.ljust(8, b'\x00'))[0] >> 43
1206656

请注意,我们将填充添加到另一侧,并将其向左移动43位(您的3位加上5个字节用于我们不需要查看的填充数据)。

请注意,int.from_bytes() 不需要填充,并且也可以处理大于 8 的字节大小。 - Martijn Pieters

3
另一种适用于任意长度字节序列的方法是使用bitstring库,它允许对bitstrings进行按位操作,例如: bitstring
>>> import bitstring
>>> bitstring.BitArray(bytes=b'\x93\x4c\x00') >> 3
BitArray('0x126980')

0
您可以将字节转换为整数,然后乘以或除以2的幂来进行移位。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接