3

我正在使用 PySerial (Python 2.7) 从这样的设备读取信息:

缓冲区 += ser.read(3)

现在我在缓冲区中有三个字节(即 0xAE0259),它的类型为 str。由于我是 Python 新手,我正在寻找“pythonian”的方式来切断三个字节中最左边的(0xAE),然后将剩余的两个解释为 int。首先我想到了一个位掩码:buffer &= 0xFFFF 但是python不允许我在 str 上使用位运算符。任何将 buffer 转换为 int 的尝试也失败了。然后我读到了“位串模块”,它让我从 BitArray 中切出位范围,但我想用它来做这件事有点过头了?

4

5 回答 5

2

您需要知道多字节类型是大端还是小端,以及它是有符号还是无符号。假设这两个字节是无符号的大端短字节,我将执行以下操作:

>>> buf = '\xAE\x02\x59'
>>> from struct import unpack
>>> unpack('>BH', buf)
(174, 601)

'>' 表示大端。'B' 是您不想要的第一个无符号字节。'H' 是一个无符号短。

于 2011-07-06T19:14:23.683 回答
1

有两种简单的方法可以做到这一点。一种方法是将缓冲区转换为十六进制整数,并使用位掩码获取最后 32 位。另一种是使用切片运算符获取最后 4 个字符,并将余数解释为十六进制整数。

>>> buffer = 'AE0259'
>>> print int(buffer, 16) & 0xFFFF
601
>>> print int(buffer[-4:], 16) 
601

编辑 - eryksun 有正确的答案,但我想针对实际用例更新我的示例。

>>> buffer = '\xAE\x02\x59'
>>> # print the integer value of the last two binary "characters"
>>> print sum((ord(x) << i*8 for i,x in enumerate(buffer[:-2-1:-1])))
601
>>> # print the integer value all binary "characters" 
>>> # with a bitmask of the lower 32 digits
>>> print sum((ord(x) << i*8 for i,x in enumerate(buffer[::-1]))) & 0xFFFF
601
于 2011-07-06T14:01:30.533 回答
1

如果您只需要进行字节解包,那么struct模块就是您的朋友(请参阅 eryksun 的回答),bytearray类型如下:

>>> ba = bytearray('\xae\x02\x59')

这允许您在字节级别进行索引和切片

>>> hex(ba[0])
'0xae'
>>> ba[1:3]
bytearray(b'\x02Y')

就将多个字节转换为整数而言,这非常有帮助,但struct除非您有一些不寻常的字节长度,否则您不太可能获得太多收益。您将两字节转换为 int 变为:

>>> (ba[1] << 8) + ba[2]
601

您在评论中说您也想要一种按位切片的一般方法。恐怕没有 - 你最好的起点是从字节数组中转移和屏蔽。这就是为什么像位串这样的模块很有用(顺便说一句,我写了它)——你让别人来做所有乏味的容易出错的事情!

>>> b = bitstring.Bits(ba)
>>> b[8:].uint
601
>>> b.unpack('hex:8, uint:16')
['ae', 601]
于 2011-07-07T21:57:35.720 回答
0

如果buffer是一个字符串,您可以通过修剪字符串来“切断”剩余的字符,如下所示:

newstr = buffer[1:]
于 2011-07-06T13:34:36.613 回答
0

@ironchefpython 建议您应该使用什么,除了您的评论表明您的缓冲区实际上由二进制数据组成。假设是这种情况,这个解决方案应该可以工作,尽管它不是很优雅:

from struct import unpack
def strmask(buffer, mask):
   #calculate the number of bytes to extract
   mask_length = mask.bit_length() / 8  + (1 if mask.bit_length() % 8 > 0 else 0)
   #extract those bytes and put them into a Python int, then perform the mask
   return mask & reduce(lambda l,r: (l<<8)+r, unpack("B" * mask_length, buffer[-1 * mask_length:]))

这会产生您想要的结果 - 例如:

>>> print strmask('\xAE\x02\x59', 0xFFFF)
601
于 2011-07-06T19:11:37.187 回答