我想解压缩一个包含9个数字的数据包,每个数字都是2个补码格式,包含3个字节。因此我的包中有27个字节。
我有这个,这允许我使用struct.unpack
4字节数字,但我的数字乘以16。
工作但输出乘以16
data = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
a = a[:3] + [0] + a[3:6] + [0] + a[6:9] + [0] + a[9:12] + [0] + a[12:15] + [0] + a[15:18] + a[18:21] + [0] + [0] + a[21:24] + [0] + a[24:27] + [0]
ch0, ch1, ch2, ch3, ch4, ch5, ch6, ch7, ch8 = struct.unpack('>lllllllll', bytearray(a))
对于4个字节的2的补码,我必须在负数的前面添加0xFF,在正数的前面添加0x00。
有没有聪明的方法来执行该操作?最有效的方法是什么?
答案 0 :(得分:2)
您可以使用辅助函数来扩展第三个字节的符号位,使其成为第四个字节:
import struct
data = [0x00, 0x00, 0x00,
0xff, 0xff, 0xff,
0x00, 0x00, 0x02,
0xff, 0xff, 0xfd,
0x00, 0x00, 0x04,
0xff, 0xff, 0xfb,
0x00, 0x00, 0x06,
0xff, 0xff, 0xf9,
0x00, 0x00, 0x08]
signed = lambda v: [0xff if v & 0x80 else 0x00,]
ch = [struct.unpack('>i', ''.join(map(chr, signed(data[i]) + data[i:i+3])))[0]
for i in range(0, len(data), 3)]
print(ch) # -> [0, -1, 2, -3, 4, -5, 6, -7, 8]
答案 1 :(得分:1)
我建议将3字节值解析为单个带符号字节和无符号(16位)短路。然后,您可以使用数学运算符将它们重新组合成单个数字。
这是一个列表理解,可以一步完成(给定s
作为bytearray
或bytes
字符串):
[(a<<16) + b for a, b in zip(*([iter(struct.unpack('>'+'bH'*9, s))]*2))]
最里面的部分使用struct.unpack
进行上述解析。然后我在相同迭代器的两个副本上使用zip
来获取字节/短对(这是一个很好的技巧!),并在将字节加到一起之前将字节左移16位。
如果你已经将你的字节作为无符号整数,你甚至不需要使用struct.unpack
,你可以直接将它们组合成三个一组(只需要一点点逻辑就可以使符号正确第一个字节):
[((a if a < 128 else a-256)<<16) + (b<<8) + c for a, b, c in zip(*([iter(data)]*3))]
答案 2 :(得分:1)
如果您使用的是Python 3,请使用类方法int.from_bytes
。它可以处理任何长度的字节簇:
#!python3
data = bytes([0,0,0,0xff,0xff,0xff,0,0,1,0xff,0xff,0xfe,0,0,3,0xff,0xff,0xfd,0,0,4])
for i in range(0,len(data),3):
print(int.from_bytes(data[i:i+3],'big',signed=True))
输出:
0
-1
1
-2
3
-3
4
还有to_bytes
,如果您还需要生成它们:
>>> (-2).to_bytes(3,'big',signed=True)
b'\xff\xff\xfe'