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