Python - 将二进制解码为布尔值
我正在尝试通过套接字接收一些数据,然后将这些数据解包以便处理。
我接收到的数据是一个二进制字符串,格式是:
"消息ID - 发送者 - 大小 - 时间1 - 时间2 - 保留 - 布尔值1 - 布尔值2"
具体的格式是:
"H - H - L - f - I - L - '布尔' - '布尔'"
当我收到数据后,我需要用这一行代码来解包:
messageEnaKill = struct.unpack('!HHLfIL??', messageEnaKill_raw)
然后我需要处理布尔值(最后两个)。问题是我不知道布尔值的格式,它是字符('c')还是别的什么?
我的第二个问题是,我需要检查这个二进制布尔值是True还是False。我该怎么做?这个代码对吗:
if msg[0] == bin(True):
假设“msg[0]”是从“解包”得到的布尔数据。
谢谢你的支持!
2 个回答
1
你可以把多个布尔值(真或假)放进一个整数里,然后进行打包和解包。
如果你想把布尔值列表转换成整数,可以用以下的函数:
def encode_booleans(bool_lst):
res = 0
for i, bval in enumerate(bool_lst):
res += int(bval) << i
return res
def decode_booleans(intval, bits):
res = []
for bit in xrange(bits):
mask = 1 << bit
res.append((intval & mask) == mask)
return res
测试时可以使用:
>>> blst = [True, False, True]
>>> encode_booleans(blst)
5
>>> decode_booleans(5, 3)
[True, False, True]
>>> decode_booleans(5, 10)
[True, False, True, False, False, False, False, False, False, False]
编码
编码的过程分为两个步骤:
- 把一组布尔值转换成一个整数。
- 创建一个结果结构,使用所有其他类型的数据加上刚刚得到的整数进行打包。
解码
解码的过程也是两个步骤,不过顺序正好相反:
- 把数据解包成预期的结构,其中布尔值用一个整数表示。
- 把这个整数解码成一组布尔值。
这假设你已经掌握了编码的部分。
完整示例
假设你已经执行了 import struct
,并且上面的两个函数已经定义:
>>> packform = "!HHLfILB"
>>> msg_id = 101
>>> sender = 22
>>> size = 1000
>>> time1 = 123.45
>>> time2 = 222
>>> bool1 = True
>>> bool2 = False
>>> bools_enc = encode_booleans([bool1, bool2])
>>> bools_enc
1
>>> resrv = 55
>>> msg_lst = [msg_id, sender, size, time1, time2, resrv, bools_enc]
>>> enc = struct.pack(packform, *msg_lst)
>>> enc
'\x00e\x00\x16\x00\x00\x03\xe8B\xf6\xe6f\x00\x00\x00\xde\x00\x00\x007\x01'
>>> decoded = struct.unpack(packform, enc)
>>> decoded
(101, 22, 1000, 123.44999694824219, 222, 55, 1)
>>> msg_lst
[101, 22, 1000, 123.45, 222, 55, 1]
>>> new_msg_id, new_sender, new_size, new_time1, new_time2, new_resrv, new_bools_enc = decoded
>>> new_bool1, new_bool2 = decode_booleans(new_bools_enc, 2)
>>> new_bool1
True
>>> new_bool2
False
4
来自 struct 文档:
‘?’ 这个转换代码对应于 C99 中定义的 _Bool 类型。如果这个类型不可用,就用一个字符来模拟。在标准模式下,它总是用一个字节来表示。
?
类型会被解包为布尔类型:
>>> type(struct.unpack('?','c')[0])
<type 'bool'>
除了空字符('\0'
)以外的任何值都会被认为是 True。所以你可以按照 Jan Vlcinsky 的建议来做。你的解决方案取决于你收到的数据。如果空字节代表 False,而其他字节代表 True,那么你可以继续使用 ?
解包作为最简单的解决方案。
所以,要检查消息中的第一个布尔值是否为真,可以使用这个测试:
messageEnaKill = struct.unpack('!HHLfIL??', messageEnaKill_raw)
if(messageEnaKill[7]==True):
# do something