如何在字节文件中用'\'替换'\\'?

How to replace the ' \\ ' with ' \ ' in a bytes file?

这是我的问题:我有一个这样的加密字节文件:

[w\x84\x7f@\xc6\xab\xc8

我想用 PyCrypto 解密,但是我发现了一个混淆的错误,如下所示:

代码在这里:

from Crypto.Cipher import DES
key = 'jsfghutp'
cipher = DES.new(key, DES.MODE_ECB)
s = open('d:/Thu-Aug-2018.bin','rb').read()

cipher.decrypt(s)

如果我运行这个,它会抛出一个错误:

ValueError                                Traceback (most recent call last)
<ipython-input-3-4fcf0e8076ca> in <module>()
----> 1 cipher.decrypt(s)

D:\Python\anaconda\lib\site-packages\Crypto\Cipher\blockalgo.py in 
decrypt(self, ciphertext)
    293             return res
    294 
--> 295            return self._cipher.decrypt(ciphertext)
    296 

ValueError: Input strings must be a multiple of 8 in length

我打印 s 的值:

s =  b'[w\x84\x7f@\xc6\xab\xc8'

然而这是不对的,我需要的是下面的结果:

>>> cipher.decrypt(b'[w\x84\x7f@\xc6\xab\xc8')
b'test aaa'

也就是说,我认为我必须将字节文件中的\\替换为\,但我没有用正确的方法来做。有谁知道如何解决这个问题?

这是因为文件包含字节字符串的文本表示 ([w\x84\x7f@\xc6\xab\xc8),但实际上并不包含字节本身。您是否正确写入文件:

with open('/tmp/file', 'wb') as f:
    f.write(b'[w\x84\x7f@\xc6\xab\xc8')

那么您阅读起来就没有问题了:

>>> with open('/tmp/file', 'rb') as f: f.read()
<<< b'[w\x84\x7f@\xc6\xab\xc8'

或通过 ast.literal_eval 解释保存在您文件中的表示,尽管在这种情况下这确实不可取。

底线是:始终知道您使用的是什么类型 - 字符串 (unicode) 或字节,并且请记住,当您在控制台中打印字节时,您会看到表示形式(类似于 \xa0东西),而不是字节本身,因为有些字节没有可打印的形式。

您的文件中没有双反斜杠。当您查看 bytes 对象的 repr 时,它会显示所有转义的反斜杠,以避免混淆,例如 \n(换行符)和 \n(反斜杠)然后是 n).

例如:

>>> s = rb'\x84'
>>> s
b'\x84'
>>> s[0]
92
>>> chr(s[0])
'\'

所以,您所问的问题不存在。您的文件中只有一个反斜杠。


实际问题是您不想要四个字节的反斜杠 x、8 和 4,您想要单个字节 b'\x84',也就是 chr(0x84)。但是这四个字节是您文件中的内容。

所以你的错误存在于你用来创建这个文件的任何代码中。不知何故,您没有将字节转储到文件中,而是转储了这些字节的反斜杠转义字符串表示形式。修复它的正确位置是在创建文件的代码中。不写入损坏的数据总是比写入损坏的数据,然后试图弄清楚如何恢复它要好。

但如果为时已晚——例如,如果您使用那段损坏的代码加密了一堆您无法再访问的明文,而现在您需要尝试恢复它——那么这种转换恰好是可逆的。您只需分两步完成。


首先,您使用反斜杠转义或更通用的 unicode 转义编解码器对字节进行解码:

>>> s=rb'[w\x84\x7f@\xc6\xab\xc8'
>>> s
b'[w\x84\x7f@\xc6\xab\xc8'
>>> s.decode('unicode-escape')
'[w\x84\x7f@Æ«È'

然后将每个 Unicode 字符转换为与相同数字匹配的字节,或者显式:

>>> bytes(map(ord, s.decode('unicode-escape')))
b'[w\x84\x7f@\xc6\xab\xc8'

… 或者,有点笨拙,依靠 Python 对 Latin-1 的解释:1

>>> s.decode('unicode-escape').encode('latin-1')
b'[w\x84\x7f@\xc6\xab\xc8'

同样,这些反斜杠实际上并不在字符串中,这正是 Python 表示 bytes 的方式。例如,如果你把它放在 b 中,hex(b[2]) 是字节 \x840x84,而不是反斜杠字符的 0x5c


你的创建代码才是真正的问题:

with open(file,'a') as f:

    f.write(str(encrypt_text).split("b'")[1].split("'")[0])
    f.close()

您正在将字节转换为它们的字符串表示形式 - 使用 b 前缀、引号和反斜杠转义每个不可打印的 ASCII 字节,然后剥离 b 和引号,然后通过将其写入文本模式文件将整个内容编码为 UTF-8。

您要做的只是以二进制模式打开文件并将字节写入其中:

with open(file, 'ab') as f:
    f.write(encrypt_text)

(另外,您不想调用 f.close()with 语句已经解决了这个问题。)

然后您可以以二进制模式读取文件并按原样解密字节。

(或者,如果您真的希望文件是可人工编辑的或类似的东西,您想要选择一种设计为可人工编辑且易于逆转的格式,例如 hexlifybase64,而不是“Python 为表示 bytes 对象以进行调试所做的任何事情”。)


1.对于 Latin-1 中的所有字符,Unicode 保证与 Latin-1 一致。 Python 将其解释为意味着 Latin-1 应该将 0-255 中的每个字节编码为代码点 0-255,而不仅仅是 ISO-8859-1 中实际定义的那些。这是有效的,因为 ISO-8859-1 没有说明如何处理它没有定义的字节,但并不是每个工具都会同意 Python.