【问题标题】:Decoding a Huffman code with a dictionary用字典解码霍夫曼码
【发布时间】:2015-10-12 20:28:59
【问题描述】:

我需要使用包含 ASCII 和 Huffman 位之间的翻译的文件来解码我用我的程序编码的 Huffman 代码。我已经在程序中有一本从“代码”到像这样的 ASCII 的字典:

{'01110': '!', '01111': 'B', '10100': 'l', '10110': 'q', '10111': 'y'}

我创建了函数:

def huffmanDecode (dictionary, text) :

这需要字典和代码。我尝试在字典中搜索关键字的文本并使用 string 中的 replace 方法和 re 中的 sub em> 但他们都没有正确解码消息。 例如,如果代码是:

011111011101110

应该可以直接解码为:

By!

但我无法通过迭代代码并在字典中搜索匹配项来做到这一点!

如何通过在文本中找到键并将其替换为值来使用字典中的键及其值对代码进行解码?

非常感谢任何帮助。

【问题讨论】:

  • 然后显示您的解码代码。手动:011111011101110 -> 01111 = B,10111 = y,和01110 = !,都根据你自己的表正确。

标签: python huffman-code


【解决方案1】:

使用bitarray 模块,您可以免费获得霍夫曼编码/解码,而且可能比其他任何东西都更有效:

from bitarray import bitarray

huffman_dict = {
    '!': bitarray('01110'), 'B': bitarray('01111'),
    'l': bitarray('10100'), 'q': bitarray('10110'),
    'y': bitarray('10111')
}

a = bitarray()
a.encode(huffman_dict, 'Bylly!')
print(a)

dec = bitarray('011111011101110').decode(huffman_dict)
print(dec)
print(''.join(dec))

# # output:
# bitarray('011111011110100101001011101110')
# ['B', 'y', '!']
# By!

如果您不想安装该模块,请阅读以下部分。


这是一个使用 huffman 树 进行解码的变体 - 该程序可以工作,但可能有更好的变体来表示二叉树(我选择了一个元组)。

当您的代码字长度不同时,此版本可能更适合。二叉树的另一个好处是,这里的代码很明显是无前缀的。

您的树形代码如下所示(过度缩进以使树形结构可见):

huffman_tree = \
    (   # 0
        (   # 00
            None,
            # 01
            (   # 010
                None,
                # 011
                (   # 0110
                    None,
                    # 0111
                    (   # 01110
                        '!',
                        # 01111
                        'B')))),
        # 1
        (   # 10
            (   # 100
                None,
                # 101
                (   # 1010
                    (   # 10100
                        'l',
                        # 10101
                        None
                    ),
                    # 1011
                    (   # 10110
                        'q',
                        # 10111
                        'y'))),
            # 11
            None))

使用它你可以解码:

def huffman_decode(strg):
    ret = ''
    cur_node = huffman_tree
    for char in strg:
        cur_node = cur_node[int(char)]
        if cur_node is None:
            raise ValueError
        elif isinstance(cur_node, str):
            ret += cur_node
            cur_node = huffman_tree
    return ret

print(huffman_decode('011111011101110'))

如果解码命中None 发生一些错误并引发ValueError。一旦解码命中一个字符串,当前节点cur_node 就会重置为“根节点”,并且游戏从树的开头开始。

因为我可以:这是你的(不完整的)霍夫曼树的可视化显示(这可能有助于理解算法的作用:每当你遇到0:向右+向下;每当你遇到@987654332 @: 向右+向上);如果你击中一个结束节点:返回该节点的字符并在根节点重新启动。

【讨论】:

  • 很好,学到了新东西。但是为什么你认为re.match/startswith 方法不适用于可变长度位序列?似乎对我来说工作得很好。哈夫曼代码背后的想法不是没有代码是另一个代码的前缀吗?
  • @tobias_k 当然,前缀都是不同的。但如果您有传输错误(以及允许重新同步的霍夫曼代码),我发现树方法更适合。但你是对的:从我的答案中删除了“不适合的正则表达式”部分......虽然没有考虑效率。是吗?
【解决方案2】:

不确定您尝试了什么,但 re.subreplace 可能不起作用,因为它们不一定从字符串的开头替换。您必须查看字符串以什么代码开头,然后替换该代码,然后继续处理字符串的其余部分。

例如,像这样:

def huffmanDecode (dictionary, text):
    res = ""
    while text:
        for k in dictionary:
            if text.startswith(k):
                res += dictionary[k]
                text = text[len(k):]
    return res

或递归:

def huffmanDecode (dictionary, text):
    if text:
        k = next(k for k in dictionary if text.startswith(k))
        return dictionary[k] + huffmanDecode(dictionary, text[len(k):])
    return ""

您也可以从您的代码中创建一个正则表达式并使用re.match 查找下一个:

import re
def huffmanDecode (dictionary, text):
    p = "|".join(dictionary) # join keys to regex
    res = ""
    while text:
        m = re.match(p, text)
        res += dictionary[m.group()]
        text = text[len(m.group()):]
    return res

注意:它们都没有适当的错误处理,如果代码与消息不匹配,它们都会失败或永远循环,但这应该让你开始。

【讨论】:

  • 谢谢你UUUU!!!!你是救命的人!我从星期五开始就一直在做这件事,但我想不通!你说得对,我的替换逻辑不合适,关键是从头开始搜索。
猜你喜欢
  • 1970-01-01
  • 2014-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多