从Python的构造模块中的BitStruct获取字符串

时间:2015-11-15 19:16:13

标签: python data-structures

我正在使用Python construct解析器处理一些二进制数据,但我没有按照预期的方式获取字符串。

请注意,在下面的简化示例中,我可以使用unpack或甚至只是一个切片,但我正在解析的实际数据不能完全对齐到字节边界。

一些示例代码:

from construct import BitStruct, BitField, Padding, String

struct = BitStruct("foo",
  BitField("bar", 8),
  BitField("baz", 16),
  Padding(4),
  BitField("bat", 4)
)

struct2 = BitStruct("foo",
  BitField("bar", 8),
  String("baz", 16),
  Padding(4),
  BitField("bat", 4)
)

data = "\x01AB\xCD"

print struct.parse(data)
print struct2.parse(data)

打印输出:

Container:
    bar = 1
    baz = 16706
    bat = 13
Container:
    bar = 1
    baz = '\x00\x01\x00\x00\x00\x00\x00\x01\x00\x01\x00\x00\x00\x00\x01\x00'
    bat = 13

我原以为String会将AB作为实际字符串返回给我。但是它会返回等效的二进制字符串。

如何说服构造返回实际的ASCII字符串?

2 个答案:

答案 0 :(得分:1)

我通过创建Adapter解决了这个问题。原始ASCII值被解析为整数列表,然后可以将其转换为字符串表示形式。

这不是最优雅的方式,但由于BitStruct仅在位值上运行,因此它似乎是最简单的解决方法。改进版本将解析不同长度的字符串(例如7位ASCII)。

from binascii import hexlify
from construct import BitStruct, BitField, Padding, Array, Octet, Adapter

class BitStringAdapter(Adapter):
  def _encode(self, obj, context):
    return list(ord(b) for b in obj)
  def _decode(self, obj, context):
    return "".join(chr(b) for b in obj)

struct = BitStruct("foo",
  BitField("bar", 8),
  BitStringAdapter(Array(2, Octet("baz"))),
  Padding(4),
  BitField("bat", 4)
)

data = "\x01AB\xCD"

out = struct.parse(data)
print hexlify(struct.build(out))

输出:

Container:
    bar = 1
    baz = 16706
    bat = 13
0141420d

哪个是正确的 - C字节被丢弃,因为它被标记为填充,这很好。

答案 1 :(得分:0)

python模块bitstruct也可用于解析位字段。它使用格式字符串,就像标准库结构模块一样。

格式说明符't'用于文本。

>>> from bitstruct import unpack
>>> data = b'\x01AB\xCD'
>>> unpack("u8u16p4u4", data)
(1, 16706, 13)
>>> unpack("u8t16p4u4", data)
(1, u'AB', 13)