字符串上的Python / PySerial位运算符

时间:2011-07-06 13:24:46

标签: python pyserial

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

buffer + = ser.read(3)

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

5 个答案:

答案 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