我正在使用PySerial(Python 2.7)从这样的设备读取信息:
buffer + = ser.read(3)
现在我在缓冲区中有三个字节(即0xAE0259),它是str类型。由于我是Python的新手,我正在寻找“pythonian”方法来切断三个字节的最左边(0xAE),然后将剩下的两个解释为int。 首先我想到了一个掩码:buffer& = 0xFFFF 但是python不会让我在str上使用位运算符。 任何将缓冲区转换为int的尝试都失败了。 然后我读到了'bitstring module',它让我从BitArray中切出比特范围,但我想用它做这个会有点超过顶部吗?
答案 0 :(得分:2)
您需要知道多字节类型是大端还是小端,以及它是有符号还是无符号。假设两个字节是无符号的big-endian short,我会执行以下操作:
>>> buf = '\xAE\x02\x59'
>>> from struct import unpack
>>> unpack('>BH', buf)
(174, 601)
'>'意味着大端。 'B'是您不想要的第一个无符号字节。 'H'是一张未签约的短片。
答案 1 :(得分:1)
有两种简单的方法可以做到这一点。一种方法是将缓冲区转换为十六进制整数,并使用位掩码来获取最后32位。另一种方法是使用slice运算符来获取最后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
答案 2 :(得分:1)
如果您只需要进行字节解压缩,那么struct
模块就是您的朋友(请参阅eryksun的答案),bytearray
类型为:
>>> ba = bytearray('\xae\x02\x59')
这允许您在字节级别进行索引和切片
>>> hex(ba[0])
'0xae'
>>> ba[1:3]
bytearray(b'\x02Y')
就将多个字节转换为int而言,这非常有用,但除非有一些不寻常的字节长度,否则你不可能获得超过struct
的余量。你的两个字节转换为int变为:
>>> (ba[1] << 8) + ba[2]
601
你在评论中说你也喜欢按位切片的一般方法。我担心没有一个 - 你最好的起点是从bytearray转移和屏蔽。这就是为什么像bitstring这样的模块很有用(我写的是顺便说一句) - 你让别人去做所有那些单调乏味的错误的东西!
>>> b = bitstring.Bits(ba)
>>> b[8:].uint
601
>>> b.unpack('hex:8, uint:16')
['ae', 601]
答案 3 :(得分:0)
如果buffer
是一个字符串,你可以通过修剪字符串来“切断”剩下的字符:
newstr = buffer[1:]
答案 4 :(得分: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