Как упаковать произвольную битовую последовательность в Python? - PullRequest
4 голосов
/ 21 февраля 2011

Я хочу закодировать / сжать некоторые двоичные данные изображения в виде последовательности битов. (Как правило, эта последовательность имеет длину, которая не укладывается аккуратно в целое число стандартных целочисленных типов.)

Как я могу сделать это, не теряя места? (Я понимаю, что, если последовательность битов не имеет «красивой» длины, всегда будет небольшой объем [<1 байта] оставшегося пространства в самом конце.) </p>

FWIW, я считаю, что для каждого символа, который я хочу кодировать, потребуется максимум 3 бита. Есть ли в Python какие-либо встроенные инструменты для такого рода работы?

Ответы [ 3 ]

6 голосов
/ 21 февраля 2011

Нет ничего очень удобного встроенного, но есть сторонние модули, такие как 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 '

Некоторые связанные вопросы:

3 голосов
/ 21 февраля 2011

Вы пытались просто сжать всю последовательность с помощью bz2 ?Если последовательность длинная, вы должны использовать bz2.BZ2Compressor, чтобы разрешить частичную обработку, в противном случае используйте bz2.compress для всего этого.Сжатие, вероятно, не будет идеальным, но, как правило, будет очень близко при работе с разреженными данными.

надеюсь, что это поможет.

2 голосов
/ 21 февраля 2011

Поскольку у вас есть отображение символов в 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-байтовый битовый массив.

...