如何在Python中打包任意位序列?
我想把一些二进制的图像数据编码/压缩成一串比特(也就是0和1的序列)。这串比特的长度通常不会刚好是标准整数类型的整数倍。
我该怎么做才能不浪费空间呢?我知道,如果这串比特的长度不是“整齐”的,那么最后总会有一点点空间是多余的(少于1个字节)。
顺便说一下,我估计每个我想编码的符号最多需要3个比特。Python有没有什么内置的工具可以帮我做这类工作呢?
4 个回答
2
因为你有一个符号到3位字符串的映射,所以bitarray可以很好地把符号列表转换成比特数组,也可以把比特数组转换回符号列表:
from bitarray import bitarray
from random import choice
symbols = {
'0' : bitarray('000'),
'a' : bitarray('001'),
'b' : bitarray('010'),
'c' : bitarray('011'),
'd' : bitarray('100'),
'e' : bitarray('101'),
'f' : bitarray('110'),
'g' : bitarray('111'),
}
seedstring = ''.join(choice(symbols.keys()) for _ in range(40))
# construct bitarray using symbol->bitarray mapping
ba = bitarray()
ba.encode(symbols, seedstring)
print seedstring
print ba
# what does bitarray look like internally?
ba_string = ba.tostring()
print repr(ba_string)
print len(ba_string)
输出结果是:
egb0dbebccde0gfdfbc0d0ccfcg0acgg0ccfga00
bitarray('10111101000010001010101001101110010100... etc.
'\xbd\x08\xaanQ\xf4\xc9\x88\x1b\xcf\x82\xff\r\xee@'
15
你可以看到,这个包含40个符号的列表(总共120位)被编码成了一个15字节的比特数组。
3
你有没有试过用 bz2 来压缩整个序列呢?如果序列很长,建议使用 bz2.BZ2Compressor,这样可以分块处理;如果序列比较短,就可以直接用 bz2.compress 来压缩整个内容。虽然压缩效果可能不是最完美的,但在处理稀疏数据时,通常能接近理想效果。
希望这能帮到你。
8
内置的功能并不是特别方便,不过有一些第三方模块,比如bitstring和bitarray,它们是专门为这个目的设计的。
from bitstring import BitArray
s = BitArray('0b11011')
s += '0b100'
s += 'uint:5=9'
s += [0, 1, 1, 0, 1]
...
s.tobytes()
如果你想把一系列3位二进制数字(也就是从0到7的数字)连接在一起,可以使用下面的方法:
>>> symbols = [0, 4, 5, 3, 1, 1, 7, 6, 5, 2, 6, 2]
>>> BitArray().join(BitArray(uint=x, length=3) for x in symbols)
BitArray('0x12b27eab2')
>>> _.tobytes()
'\x12\xb2~\xab '
这里有一些相关的问题: