如何在 python 中将具有不可打印字符的字节字符串转换为十六进制?

How to convert byte string with non-printable chars to hexadecimal in python?

我有一个 ANSI 字符串 Ď–ór˙rXüď\ő‡íQl7,我需要像这样将它转换为十六进制: 06cf96f30a7258fcef5cf587ed51156c37(用 XVI32 转换)。

问题是 Python 无法正确编码所有字符(其中一些甚至在这里,在 Stack Overflow 上显示不正确)所以我必须用字节字符串处理它们。

所以上面的字符串是以字节为单位的:b'\x06\xcf\x96\xf3\nr\x83\xffrX\xfc\xef\\xf5\x87\xedQ\x15l7'

这就是我需要转换为十六进制的内容。

到目前为止我试过 binascii 没有成功,我试过这个:

h = ""
for i in b'\x06\xcf\x96\xf3\nr\x83\xffrX\xfc\xef\\xf5\x87\xedQ\x15l7':
    h += hex(i)
print(h)

它打印:

0x60xcf0x960xf30xa0x720x830xff0x720x580xfc0xef0x5c0xf50x870xed0x510x150x6c0x37

好的。看来我有所进展...但是 0x 是怎么回事?

当我像这样从字符串中删除 0x 时:

h.replace("0x", "")

我得到 6cf96f3a7283ff7258fcef5cf587ed51156c37 看起来是正确的。

但有时字节字符串在 x 旁边有一个 0,它会从字符串中删除,从而导致不正确的十六进制字符串。 (上面的字符串开头缺少 0)。

有什么想法吗?

根据文档,hex()“整数转换为前缀为‘0x’的小写十六进制字符串。”因此,当使用 hex() 时,您总是会得到一个 0x 前缀。如果你想连接多个十六进制表示,你将始终必须删除它。

But sometimes the byte string has a 0 next to a x and it gets removed from the string resulting in a incorrect hexadecimal string. (the string above is missing the 0 at the beginning).

这没有任何意义。 x 不是有效的十六进制字符,因此在您的解决方案中,它 只能 hex() 调用生成。而且,如上所述,将始终创建一个 0x。所以序列 0x 可以 never 在你的结果字符串中以不同的方式出现,所以用什么替换 0x 应该很好。

您的解决方案中的实际问题是 hex() 不强制使用两位数的结果,如以下示例所示:

>>> hex(10)
'0xa'
>>> hex(2)
'0x2'

所以在你的情况下,由于字符串以 b\x06 开头,代表数字 6hex(6) 仅 returns 0x6,所以你只在这里得到一个数字,这是你问题的真正原因。


您可以做的是使用格式字符串执行到十六进制的转换。这样你既可以省略前缀又可以强制使用两位数的长度。然后,您可以使用 str.join 将其全部组合成一个十六进制字符串:

>>> value = b'\x06\xcf\x96\xf3\nr\x83\xffrX\xfc\xef\\xf5\x87\xedQ\x15l7'
>>> ''.join(['{:02x}'.format(x) for x in value])
'06cf96f30a7283ff7258fcef5cf587ed51156c37'

此解决方案不仅适用于字节字符串,而且适用于任何可以格式化为十六进制字符串的内容(例如整数列表):

>>> value = [1, 2, 3, 4]
>>> ''.join(['{:02x}'.format(x) for x in value])
'01020304'

如果你是 运行 python 3.5+,bytes 类型有一个新的 bytes.hex() 方法,returns 字符串表示。

>>> h = b'\x06\xcf\x96\xf3\nr\x83\xffrX\xfc\xef\\xf5\x87\xedQ\x15l7'
b'\x06\xcf\x96\xf3\nr\x83\xffrX\xfc\xef\\xf5\x87\xedQ\x15l7'
>>> h.hex()
'06cf96f30a7283ff7258fcef5cf587ed51156c37'

否则你可以使用binascii.hexlify()做同样的事情

>>> import binascii
>>> binascii.hexlify(h).decode('utf8')
'06cf96f30a7283ff7258fcef5cf587ed51156c37'