У меня возникла проблема с тем, как преобразовать строку кодировки huffman в двоичный python.
Этот вопрос не содержит ничего из алгоритма хаффмана.
Это так:
Я могу получить закодированную строку хаффмана, скажем, 01010101010
. Обратите внимание, что это строка.
Но теперь я хочу сохранить представление строки в реальном двоичном файле.
В закодированной строкой huffman каждые 0 и 1 являются байтами.
Я хочу, чтобы каждый 0 и 1 был немного.
Как я могу это сделать в python?
Изменить 1:
Пожалуйста, простите, я не описал свою проблему достаточно ясно.
Позвольте мне объяснить мой нынешний подход к написанию нулей и единиц в двоичный файл.
Скажем, мы можем ввести строку кода s = '010101010'.
int
чтобы преобразовать его в integerunichr
чтобы преобразовать его в строку, чтобы я мог записать его в файлТакже следует отметить, что мне нужно прочитать файл, чтобы декодировать код huffman.
Поэтому мой подход,
И на шаге 2 проблема возникает, и я стал невежественным.
Поскольку некоторые строки хаффмана могут быть короткими (например, 10
), а некоторые могут быть длинными (010101010101001
). Это приводит к их разной длине байтов в их значении int (некоторая короткая строка может принимать только один байт, а длинные - две или даже больше)
Следующий код иллюстрирует мою проблему:
ss=['010101','10010101010']
# first one is short and takes only one byte in its int value
# second one is long and takes two bytes
print 'write it to file'
with open('binary.bin','wb') as f:
for s in ss:
n=int(s,2)
print n
s=unichr(n)
f.write(s)
print 'read it to file'
with open('binary.bin','rb') as f:
for s in f.read():
print ord(s)
Я читаю один байт во второй раз с частью, но на самом деле это неверно. Потому что строка 10010101010
занимает два байта.
Итак, когда я читаю эти байты из файла, сколько байтов я должен прочитать сразу?
Один из возможных подходов (с использованием библиотеки bitstring), который имеет определенный смысл, но по-прежнему содержит некорректность:
Используйте библиотеку битовых строк (благодаря механической улитке и марку B)
Для записи в файл.
шаги:
Для чтения:
Код:
ss=['01010100','10010101010','010101110101010101'] #encoded message
from bitstring import BitArray,BitStream
print 'write it to file'
with open('binary.bin','wb') as f:
s=''.join(ss);
b=BitArray(bin=s)
f.write(b.tobytes())# thanks to Scott, tobytes() method is very useful
print 'read it to file'
b=BitArray(filename='binary.bin')
print b.bin
0x0a92a95d55
в файл вместо 5 байтов \n\x92\xa9]U
Вы могли бы просто написать 01010100...
в файл! Я бы посоветовал использовать метод b.tobytes()
для преобразования в байты (которые b.tobytes()
нулевыми битами до границы байта). Эти дополнительные биты в конце могут быть проигнорированы декодером, так как они не будут декодироваться ни к одному символу. Также важно дополнять в конце, а не в начале.
f.write(BitArray(bin=''.join(ss)).tobytes())
а для чтения вы можете использовать BitArray(filename='binary.bin')
или создать его из чтения -только файл объекта BitArray(f)
.
В Python есть два разных "двоичных" представления, которые вы, возможно, захотите использовать.
Один из них является "бигнем" или целым числом произвольной точности. Этот тип называется long
в Python 2.x и int
в Python 3.x. Как следует из названия, это представление семантически является целым числом произвольной длины, поэтому полезно, если вы планируете делать арифметику по полученному числу. Чтобы проанализировать строку двоичных цифр, используйте
# Python 2
long(digit_str, 2)
или
# Python 3
int(digit_str, 2)
bitstring
В качестве альтернативы, как предлагает Marc B в комментариях, используйте библиотеку bitstring
. В частности, для преобразования используйте функцию bitstring.pack
.
Для кодирования Хаффмана использование bitstring
, вероятно, предпочтительнее хранения данных в byte
-string, поскольку коды Хаффмана обычно не кратно 8 бит; bitstring
позволяет вам манипулировать бит -string s произвольной длины. Недостаток: bitstring
не входит в стандартную библиотеку.
У вас есть строка, которую нужно преобразовать в число. int
принимает необязательную "базу" в качестве аргумента. Итак, для строки в вашем примере,
>>> int('01010101010', 2)
682
Когда у вас есть номер (а не строка), не имеет смысла хотеть "реальный" двоичный код, так как номер один и тот же, вы можете отображать его на любой базе. Это означает, что двоичный код 100
- это то же число, что и десятичное число 4
, внутри вашей программы они не разные числа. Итак, как только вы превратите свою строку в число, вы можете играть с битами в ней.
'01'
и '1'
это разные коды. Вам необходимо кодировать количество битов, а также значение битов.