把ascii字节串打包成bitmap/bitstring回string?
Ascii string of bytes packed into bitmap/bitstring back to string?
我有一个打包的字符串,每个字符最初都是一个无符号字节,但存储为 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
这花了我一段时间才弄清楚,因为您的解决方案似乎忽略了第一位数据。给定输入字节 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
的 cythonised 版本)。
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,则需要进行一些调整。我在要替换的行之后将它们添加为注释并标记为 python 2
.
我有一个打包的字符串,每个字符最初都是一个无符号字节,但存储为 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
这花了我一段时间才弄清楚,因为您的解决方案似乎忽略了第一位数据。给定输入字节 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
的 cythonised 版本)。
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,则需要进行一些调整。我在要替换的行之后将它们添加为注释并标记为 python 2
.