将 bytes 对象中的双反斜杠替换为单反斜杠

Replace double backslashes with single backslashes in a bytes object

提问人:Hypherix 提问时间:10/4/2023 最后编辑:Hypherix 更新时间:10/5/2023 访问量:76

问:

我正在编写一个程序,其中我处理bytes对象。程序生成一个 bytes 对象(来自字符串),其中的一部分是随机生成的(如果我运行程序两次,bytes 对象的一部分看起来会不同,另一部分总是相同的)。bytes 对象始终包含多个双反斜杠,在程序的某一部分,我想用单反斜杠替换它们。

我遇到的问题是,有时我成功地替换了双反斜杠,有时字节对象中的字符会完全错误。

我用单反斜杠替换双反斜杠的方法本质上是使用解码和编码,正如有类似问题的帖子中的建议一样。以下示例显示了何时按预期工作:

string1 = '\\xeb\\x97\\x01\\x00\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x00'
bytes_double_back = string1.encode(encoding='ascii')    # b'\\xeb\\x97\\x01\\x00\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x00'
bytes_single_back = bytes_double_back.decode('unicode_escape').encode('raw_unicode_escape')   # b'\xeb\x97\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00'

但是,当再次运行程序时,这次的字符串看起来略有不同,但会出现问题:

string1 = '\\x3d\\x5b\\x01\\x00\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x00'
bytes_double_back = string1.encode(encoding='ascii')    # b'\\x3d\\x5b\\x01\\x00\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x00'
bytes_single_back = bytes_double_back.decode('unicode_escape').encode('raw_unicode_escape')   # b'=[\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00'

在这里,bytes_single_back确实摆脱了双反斜杠,但它的开头没有正确转换。

我做错了什么?提前致谢!

python-3.x 字符串 字符编码

评论

0赞 Giacomo Catenazzi 10/4/2023
有时反斜杠是真实的,有时只是打印在终端中,因为它无法打印原始字符。保存到文件中,以便您知道是否有黑斜杠,或者只是控制代码。仅从输出中通常无法区分两者
0赞 Hypherix 10/4/2023
我之前在努力解决问题时已将变量保存到文件中以检查这一点,并且反斜杠实际上就在那里

答:

1赞 chrslg 10/5/2023 #1

开头似乎正确地转换到我身上。请注意,字节字符串不只包含转义的十六进制代码。有时十六进制码可以在 ASCII 中打印。 被打印出来。这与 See 相同"hello".encode()b'hello'b'\x68\x65\x6c\x6c\x6f'b'hello'==b'\x68\x65\x6c\x6c\x6f'

因此,在您的情况下,恰好与 .为什么python会打印长版本,而短版本可以?b'\x3d\x5b'b'=[

然后,当然,其余的,没有同义词(没有表示 ascii charb'\x01\x00\x00\x01...b'\x01')

再次检查.相同的 4 个字节长字节串中的相同 4 个字节。只有两种方法可以编写相同的字节字符串。b'\x3d\x5b\x01\x00'==b'=[\x01\x00'

所以,简而言之,这就是字节串在屏幕上打印的方式。with for 字节,没有 ascii 表示形式。当该字符明确时,对某些字符的 ascii 代码或直接作为单个字符的字节进行转义。 例如,默认情况下打印为 因为 0x27 是 的 ascii 代码。同样是打印的,因为0x22是 的 ascii 代码。但打印为 .它用于将字节字符串括起来,然后需要转义字符。\x01b'\x27'b"'"'b'\x22'b'"""b'\x27\x22'b'"\''''

评论

0赞 Hypherix 10/5/2023
很好的解释!您对用什么编码字符串而不是 ascii 来使这项工作有任何建议吗?
0赞 chrslg 10/5/2023
@Hypherix我可能缺乏一些背景。因为我的观点是:它已经在工作了。我的意思是,如果你的目标是拥有正确的字节串,那么,好消息,你就有了。或者你有没有理由需要打印它(我说“打印它”,因为只有在打印时才重要。在内存中与 完全相同。这些只是 2 个字节,相同)。我的印象是,你的目标是以字节串结束(你的代码的最后一行是计算字节串)。b'\x3d\x5b'b\=['
0赞 chrslg 10/5/2023
@Hypherix。但也许你想要的是一个字节串的表示形式(所以一个字符串。文本。但这根本不是你计算的)。是吗?因为只有在决定如何打印这两个字节时,您才可以选择将其打印为 或 .而且这些信息不是字节串的一部分。这是一种打印选择。同样,即使是您的评论(我正在回复的评论)也会询问“您对用什么对字符串进行编码有任何建议”。这也让我相信存在误会。这就是编码(...b'\x3d\x5b'b'=['
0赞 chrslg 10/5/2023
(...)决定将 2 个字节 61 和 91(又名 0x3d 和 0x5d)打印为 or as 是解码决定,而不是编码决定(解码≡从一堆字节创建字符串表示形式。 编码≡从字符串创建一堆字节)。b'\x3d\x5d'b'=['
0赞 chrslg 10/5/2023
我能想到的最接近的事情,如果你真的需要获取字符串(而不是字节串。同样,您已经拥有的字节串,即使它显示在控制台中) ,也是方法。一旦你有了byestring(并且,你又有了它),就是一个字符串,所有字节都是十六进制的。但是没有 .b'\x3d\x5b'b'=['\x3d\x5bhexbytes_single_back.hex()\x