【问题标题】:Python encoding function can't be decodedPython编码函数无法解码
【发布时间】:2010-07-01 19:10:23
【问题描述】:

我编写了这段 Python 代码,试图将对象转换为一串 1 和 0,但解码失败,因为无法解压缩数据。这是代码:

def encode(obj):
    'convert an object to ones and zeros'
    def tobin(str):
        rstr = ''
        for f in str:
            if f == "0": rstr += "0000"
            elif f == "1": rstr += "0001"
            elif f == "2": rstr += "0010"
            elif f == "3": rstr += "0100"
            elif f == "4": rstr += "1000"
            elif f == "5": rstr += "1001"
            elif f == "6": rstr += "1010"
            elif f == "7": rstr += "1100"
            elif f == "8": rstr += "1101"
            elif f == "9": rstr += "1110"
            else: rstr += f
        return rstr
    import pickle, StringIO
    f = StringIO.StringIO()
    pickle.dump(obj, f)
    data = f.getvalue()
    import base64
    return tobin(base64.b16encode(base64.b16encode(data)))
def decode(data):
    def unbin(data):
        rstr = ''
        for f in data:
            if f == "0000": rstr += "0"
            elif f == "0001": rstr += "1"
            elif f == "0010": rstr += "2"
            elif f == "0100": rstr += "3"
            elif f == "1000": rstr += "4"
            elif f == "1001": rstr += "5"
            elif f == "1010": rstr += "6"
            elif f == "1100": rstr += "7"
            elif f == "1101": rstr += "8"
            elif f == "1110": rstr += "9"
        return rstr
    import base64
    ndata = base64.b16decode(base64.b16decode(unbin(data)))
    import pickle, StringIO
    f = StringIO.StringIO(ndata)
    obj = pickle.load(f)
    return obj

【问题讨论】:

  • 你知道 Python 有一个内置的bin() 函数吗?
  • 他的二进制字符串转换有些混乱(例如 0100 3)
  • @Tim Pietzcker: tobin 没有进行二进制转换。
  • 澄清一下:您在这里所做的不符合加密的条件——它实际上只是数据的编码。事实上,它看起来很像格雷码:en.wikipedia.org/wiki/Gray_code。它当然不能提供太多的安全性:它可能是非常简单的暴力破解。
  • 我编辑了问题以更改术语(加密→编码,解密→解码),因为这是一个严重的错误,可能会严重混淆未来的提问者。请参阅 en.wikipedia.org/wiki/Code> 和 en.wikipedia.org/wiki/Encryption> 了解更多详情。

标签: python encoding pickle decoding


【解决方案1】:

我认为有几个问题,但一个是当你解码时,你需要在你的 unbin() 函数中迭代 4 个字符组,而不是像你目前正在做的单个字符。

【讨论】:

  • 谢谢。我修复了它,让它遍历 4 个字符,现在可以正常工作了。
【解决方案2】:

我想我有一个更好的解决方案给你。这应该更加安全,因为它“加密”了所有内容,而不仅仅是数字:

MAGIC = 0x15 # CHOOSE ANY TWO HEX DIGITS YOU LIKE

# THANKS TO NAS BANOV FOR THE FOLLOWING:
unbin = tobin = lambda s: ''.join(chr(ord(c) ^ MAGIC) for c in s)

【讨论】:

  • 优化unbin = tobin 而不是def unbin :-D
  • @Nas Banov 我想知道你是否可以这样做。我根本不使用python,几乎只是从提问者那里复制语法。 :)
  • 是的,你可以。但现在我注意到你的代码中有一些东西——你不能在字符串上使用^。而且由于我们越来越变态,因此建议更换:unbin = tobin = lambda s: ''.join(chr(ord(c) ^ MAGIC) for c in s)
  • @Nas Banov 啊,我认为 for 会丢弃字符,而不是字符串。感谢您的更正。
【解决方案3】:

您的 binunbin 函数不是彼此相反的,因为 bin 有一个 else 子句,它只是将字符逐字放入输出中,但 unbin 没有 else 子句将它们传回.

【讨论】:

  • else 应该抛出异常,因为它在设计上是无法访问的 - base64.b16encode(base64.b16encode()) 确保只有数字
【解决方案4】:

顺便说一句...base64.b16encode(base64.b16encode(data)) 等价于data.encode('hex').encode('hex')。而且有更简单快捷的方法来做映射,

def tobin(numStr):
    return ''.join(("0000","0001","0010","0100","1000","1001","1010","1100","1101","1110")[int(c)] for c in numStr)

这种编码的整个想法虽然表面上看起来很复杂,但并不是很好。首先,它没有做太多的加密,因为十六进制转储中的每个数字总是匹配到相同的 0 和 1 的 8 长度字符串:

>>> hexd = '0123456789ABCDEF'
>>> s = hexd.encode('hex')
>>> s
'30313233343536373839414243444546'
>>> s=''.join(["0000","0001","0010","0100","1000","1001","1010","1100","1101","1110"][int(c)] for c in s)
>>> s
'01000000010000010100001001000100010010000100100101001010010011000100110101001110100000011000001010000100100010001000100110001010'
>>> for i in range(0,len(s),8):
...     print hexd[i/8], s[i:i+8], chr(int(s[i:i+8],2))
... 
0 01000000 @
1 01000001 A
2 01000010 B
3 01000100 D
4 01001000 H
5 01001001 I
6 01001010 J
7 01001100 L
8 01001101 M
9 01001110 N
A 10000001 
B 10000010 ‚
C 10000100 „
D 10001000 ˆ
E 10001001 ‰
F 10001010 Š

其次,它把腌制物体的大小炸了16倍!即使您通过将每 8 位 '0' 和 '1' 转换为字节(比如 chr(int(encoded[i:i+8],2)))来打包它,这仍然是 2x 泡菜。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-03-01
    • 2014-06-23
    • 2013-05-15
    • 1970-01-01
    • 2015-11-06
    • 2011-06-29
    • 1970-01-01
    • 2015-07-22
    相关资源
    最近更新 更多