あなたのソリューションはデータの最初のビットを無視しているように見えるので、これを理解するのにしばらく時間がかかりました。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
ただし、これは標準ライブラリのみを使用して非常に簡単に行うことができます。これにより、ソリューションの移植性が向上し、私が試した例では、さらに桁違いに高速になりました (私は の cythonized バージョンを試していませんでしたbitstring
)。
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
。