【问题标题】:Ascii string of bytes packed into bitmap/bitstring back to string?打包成位图/位串的 Ascii 字节串返回到字符串?
【发布时间】:2015-02-28 22:26:56
【问题描述】:

我有一个打包的字符串,每个字符最初都是一个无符号字节,但存储为 7 位,然后打包到一个无符号字节数组中。我正在尝试找到一种在 Python 中解压缩此字符串的快速方法,但我编写的使用 bitstring 模块的函数运行良好,但速度很慢。看起来这样的事情不应该那么慢,但我可能做得非常低效......

这看起来可能是微不足道的,但我只是不知道该使用什么,也许已经有一个函数可以解包字符串?

from bitstring import BitArray

def unpackString(raw):
    msg = ''

    bits = BitArray(bytes=raw)
    mask = BitArray('0b01111111')

    i = 0
    while 1:
        try:
            iByte = (bits[i:i + 8] & mask).int
            # value of 0 denotes a line break
            if iByte == 0:
                msg += '\n'
            elif iByte >= 32 and iByte <= 126:
                msg += chr(iByte)
            i += 7
        except:
            break

    return msg

【问题讨论】:

  • 您能否发布您的数据样本,以便我们确定我们为您提供有效的解决方案?
  • 当然,原始数据的示例位于:files.eas.cornell.edu/~mjs472/rawbytes.bin
  • 此外,该数据适用于 NWS 定义的天气字符串。解压后应该看起来像“...”。
  • 现在没有时间编写代码,但您可能想要做的是迭代字节,将每两个连续字节转换为一个单词(是的,字节重叠),根据需要移动,然后进行掩蔽。这应该会显着加快速度。
  • 这里,你的函数应用于你的原始数据样本(方法:unpackString(open("rawbytes.bin", "rb").read()))返回'\n\n \n\n\n,\n\n\n\n\n\n\n&lt;None&gt;\nSC.Y\nWS.W\nWS.A\n'——你确定这是正确的吗?

标签: python string bitmap bitstring


【解决方案1】:

我花了一段时间才弄清楚,因为您的解决方案似乎忽略了第一部分数据。鉴于输入字节为 129 (0b10000001),我希望看到以下打印的 64 '1000000',但您的代码会生成 1 '0000001'——忽略第一位。

bs = b'\x81' # one byte string, whose value is 129 (0x81)
arr = BitArray(bs)
mask = BitArray('0b01111111')
byte = (arr[0:8] & mask).int
print(byte, repr("{:07b}".format(byte)))

最简单的解决方案是修改您的解决方案以使用 bitstring.ConstBitStream - 我得到了以下数量级的速度提升。

from bitstring import ConstBitStream
def unpack_bitstream(raw):
    num_bytes, remainder = divmod(len(raw) * 8 - 1, 7)
    bitstream = ConstBitStream(bytes=raw, offset=1) # use offset to ignore leading bit
    msg = b''
    for _ in range(num_bytes):
        byte = bitstream.read("uint:7")
        if not byte:
            msg += b'\n'
        elif 32 <= byte <= 126:
            msg += bytes((byte,))
            # msg += chr(byte) # python 2
    return msg

但是,仅使用标准库就可以很容易地做到这一点。这使得解决方案更便携,并且在我尝试过的情况下,速度提高了另一个数量级(我没有尝试bitstring 的cythonized 版本)。

def unpack_bytes(raw, zero_replacement=ord("\n")):
    # use - 1 to ignore leading bit
    num_bytes, remainder = divmod(len(raw) * 8 - 1, 7)

    i = int.from_bytes(raw, byteorder="big")
    # i = int(raw.encode("hex"), 16) # python 2
    if remainder:
        # remainder means there are unused trailing bits, so remove these
        i >>= remainder

    msg = []
    for _ in range(num_bytes):
        byte = i & 127
        if not byte:
            msg.append(zero_replacement)
        elif 32 <= byte <= 126:
            msg.append(byte)
        i >>= 7
    msg.reverse()

    return bytes(msg)
    # return b"".join(chr(c) for c in msg) # python 2

我使用 python 3 来创建这些方法。如果您使用的是 python 2,那么您需要进行一些调整。我已将它们添加为 cmets 在它们打算替换的行之后并将它们标记为python 2

【讨论】:

  • 我喜欢你的 unpack_bytes 解决方案,但 int.from_bytes 在 python 2.7 中也不起作用。不过,您的 ConstBitStream 解决方案效果很好。
  • 为 python 2 添加了一种将字节字符串转换为整数的方法。仍然具有竞争力。
猜你喜欢
  • 1970-01-01
  • 2020-06-20
  • 1970-01-01
  • 2014-05-31
  • 1970-01-01
  • 1970-01-01
  • 2013-01-18
  • 2023-03-21
  • 2017-01-05
相关资源
最近更新 更多