使用Python将十六进制字符串转换为整数

6
请注意,问题不是将十六进制转换为十进制,而是将一串十六进制值转换为整数。
例如,我从十六进制转储中得到了一个字符串(如“6c 02 00 00”),因此我首先需要将其转换为实际的十六进制,然后获取它所表示的整数...(这个特定的数字将作为int16和int32为620)
我尝试了很多方法,但让自己更加困惑。在python中(最好是3.x)有没有快速完成此类转换的方法?

所以,提醒一下 - 不要对输入数据进行过多的篡改(即不要在数字之间添加额外的空格)- 我在答案末尾添加的编解码器+结构体方法可能会让其他人(包括我自己)认为这是“显而易见的方法”,如果没有空格的话。 - jsbueno
2个回答

11

更新 自从 Python 3.7 版本起,bytes.from_hex 将忽略空格 - 因此,直接的做法是将字符串解析为字节对象,然后作为整数查看:

In [10]: int.from_bytes(bytes.fromhex("6c 02 00 00"), byteorder="little")
Out[10]: 620

原始回答

这不仅是一个字符串,而且它是按照小端序排列的——也就是说,只需去除空格,使用 int(xx, 16) 调用即可。它也不具有实际字节值作为4个任意0-255数字的属性(在这种情况下,struct.unpack 将起作用)。

我认为一个不错的方法是将组件交换回“人类可读”顺序,并使用 int 调用——如下所示:

number = int("".join("6c 02 00 00".split()[::-1]), 16)

在这里发生了什么:表达式的第一个部分是 split - 它在空格处将字符串拆分,并提供包含四个字符串的列表,每个字符串包含两个数字。接下来是 [::-1] 特殊切片 - 它大致意思是“从前一个序列中提供一个元素子集,从边缘开始,每次倒退一个元素”- 这是 Python 中反转任何序列的常见惯用语。

这个反转后的序列被用于调用 "".join(...) - 它基本上使用空字符串作为连接器将序列中的每个元素连接起来 - 这个调用的结果是“0000026c”。有了这个值,我们只需要调用 Python 的 int 类,它接受一个可选的二进制参数,用于解释第一个参数中表示的数字。

>>> int("".join("6c 02 00 00".split()[::-1]), 16)
620

另一种选择是将每两位数字按其位置加权正确移位后的转换累加 - 这也可以使用reduce在单个表达式中完成,不过一个4行的Python for循环会更易读:

>>> from functools import reduce #not needed in Python2.x
>>> reduce(lambda x, y: x  + (int(y[1], 16)<<(8 * y[0]) ), enumerate("6c 02 00 00".split()), 0)
620

更新:原帖作者表示实际上字符串中并没有“空格”- 在这种情况下,可以使用几乎相同的方法,但是需要每两个数字进行拆分而不是使用 split() 方法:

reduce(lambda x, y: x  + (int(y[1], 16)<<(8 * y[0]//2) ), ((i, a[i:i+2]) for i in range(0, len(a), 2)) , 0)

(其中a是变量,代表您的数字,当然)- 或者使用十六进制编解码将其转换为实际的4字节内存中的数字,并使用struct解包该数字。这可能更符合您代码的语义要求:

import codecs
import struct
struct.unpack("<I", codecs.decode("6c020000", "hex") )[0]

这里的方法是将每个2个数字传递到codecs.decode调用返回的字节对象中的实际字节中,然后使用struct将缓冲区中的4个字节作为单个32位整数读取。


谢谢,实际上我已经有了没有空格的转储文件,但是为了可读性,我在这里添加了它们。无论如何,我在每2个字符后添加了空格并执行了您的一行代码,它完美地工作了...我想我过于复杂化了它,试图将其转换为正确的十六进制,然后将其馈送到像bytes.fromhex()和其他函数中。 - G.Rassovsky

6
你可以使用unhexlify()将十六进制字符串转换为二进制形式,然后使用struct.unpack()解码小端值为整数:
>>> from struct import unpack
>>> from binascii import unhexlify
>>> n = unpack('<i', unhexlify('6c 02 00 00'.replace(' ','')))[0]
>>> n

"

格式化字符串 '<i' 表示小端符号整数。您可以使用 '<I''<L' 替换为无符号整数或长整型(两者都为4个字节)。

如果数据不包含空格,则简化为:

"
>>> n = unpack('<i', unhexlify('6c020000'))[0]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接