python中的LZW压缩和解压缩

python中的LZW压缩和解压缩,python,algorithm,compression,lzw,Python,Algorithm,Compression,Lzw,我正在用python(2.7)编写基本Lempel Ziv压缩的变体。在这种情况下,该算法通常会输出一个由字符和整数组成的列表,最后一个指定字典中每个新字符串的顺序 现在,假设我们压缩一个足够大的文件,这样会出现多达400000个或更多的整数,所以我要做的是将这些整数中的每一个传递给二进制,将二进制分解为多达8位字节(例如,400000的二进制形式是一个大约18或19位的1和0的字符串,因此它可以分解为2个8位字节和1个2或3位字节),这样每个6个字符的整数将减少为3个字符的字符串。请注意,即使

我正在用python(2.7)编写基本Lempel Ziv压缩的变体。在这种情况下,该算法通常会输出一个由字符和整数组成的列表,最后一个指定字典中每个新字符串的顺序

现在,假设我们压缩一个足够大的文件,这样会出现多达400000个或更多的整数,所以我要做的是将这些整数中的每一个传递给二进制,将二进制分解为多达8位字节(例如,400000的二进制形式是一个大约18或19位的1和0的字符串,因此它可以分解为2个8位字节和1个2或3位字节),这样每个6个字符的整数将减少为3个字符的字符串。请注意,即使是3位整数也会减少为2个字符的字符串,这样LZW算法得到的列表就更紧凑了

发生的事情是,我能够正确地用代码压缩一个文件(从2.2MB到1.5MB),或者我认为是这样,但是当我解压缩它时,我没有得到完全相同的初始文本

这是我的压缩代码:

def encode(order):
    danger = [0, 9, 10, 13, 32, 222, 255, 256]
    str2 = ""
    str3 = ""
    binary = bin(order)[2:]
    for bit in binary:
        str2 += bit
        if len(str2) == 8:
            helper = int(str2,2)
            if helper in danger:
                str3 = chr(222)+str(order) #222 is choosable, may be another ASCII one
                str2 = ""
                break
            else:
                str3 += chr(int(str2,2)) 
                str2 = ""
    if str2 != "":
        helper = int(str2,2)
        if helper in danger:
            str3 = chr(222)+str(order)
        else:
            str3 += chr(int(str2,2))
    return str3

file_in = open("donquijote.txt")
file_out = open("compressed5.txt","w")

codes = dict([(chr(x), x) for x in range(256)])
danger = [0, 9, 10, 13, 32, 222, 255, 256]      
code_count = 257
current_string = ""
string = file_in.read()
for c in string:
    current_string = current_string + c
    if not current_string in codes:
        codes[current_string] = code_count
        if (codes[current_string[:-1]] < 257) & (codes[current_string[:-1]] not in danger):
            file_out.write(chr(codes[current_string[:-1]])+" ")
        else:
            str4 = encode(codes[current_string[:-1]])
            file_out.write(str4+" ")
        code_count += 1
        current_string = c
file_out.write(encode(codes[current_string]))

file_in.close()
file_out.close()
output = open("compressed5.txt")
descomp = open("decompressed5.txt","w")

text = output.read()
compressed_data = text.split()
strings = dict([(x, chr(x)) for x in range(256)])

next_code = 257
previous_string = ""
binary = ""
a = 1
for element in compressed_data:
    for char in element:
        if ord(char) == 222:
            c = int(element[1:])
            break
        else:
            binary += bin(ord(char))[2:]
            if a == len(element):
                c = int(binary,2)
                a = 1
            else:
                a += 1
    binary = ""
    if not (strings.has_key(c)):
        strings[c] = previous_string + (previous_string[0])
    descomp.write(strings[c])
    if not(len(previous_string) == 0):
        strings[next_code] = previous_string + (strings[c][0])
        next_code +=1
    previous_string = strings[c]

output.close()
descomp.close()

我看不到我在这里丢失了什么(实际上我在Python中是新手),或者我应该考虑在危险列表中添加另一个有问题的字符,以避免与“列表”格式冲突,或者我可以用另一种方式将这个列表写在一个紧凑的表单上,而不丢失它的格式。


非常感谢您提供的任何帮助!!

什么是最小的输入数据不起作用?输出是什么?1.您如何确保压缩是完美的?2.为什么不使用二进制文件访问(我不是phyton用户,但大多数语言都提供从OS API继承的二进制访问API)如果这是您的自定义压缩,您可以根据自己的需要对其进行修改,您是否考虑过类似GIF压缩(无需存储字典)的内容?另外,我会避免下面的所有ASCII
32
,因为ASCII文件访问函数也使用一些打印机转义码,这些转义码可能在文件结束前提前终止。对于延迟回复,我能够修复它-由于出现奇怪的字符,它确实进行得不顺利-我省略了其中一些,尤其是那些在32以下,结果是编码错误更少,虽然压缩也更少,所以最后对压缩数据进行编码不是一个好方法。压缩算法LZW工作得很好,唯一的问题是必须找到一种方法以这种或那种方式存储压缩数据,以使输出文件真正可用“压缩”-我通过将基数10改为更大的数字来表示整数。另外,@Spektre,GIF压缩我想你指的是哈夫曼算法…(存储字典通常是哈夫曼导数之类的)?不,LZW是一个不同的实现,我应该这样做。无论如何,谢谢你的帮助:)1.在GIF编码器/解码器中,LZW的字典是在编码和解码过程中以特殊方式动态创建的,因此它实际上不存储在图像文件中(与哈夫曼编码无关)请参阅。这样做的缺点是,您需要不时清除字典,以便LZW压缩流中有相应的命令(称为清除代码)。2.如果您使用二进制文件访问,则存储的单词以256为基数,没有任何限制。。。