如何在 Python 3 中将十六进制字符串转换为有符号整数?
我能想到的最好的是
h = '9DA92DAB'
b = bytes(h, 'utf-8')
ba = binascii.a2b_hex(b)
print(int.from_bytes(ba, byteorder='big', signed=True))
有没有更简单的方法?无符号更容易:int(h, 16)
顺便说一句,问题的根源是itunes持久id - 音乐库xml版本和iTunes十六进制版本
在 n 位二进制补码中,位具有值:
位 0 = 20
位 1 = 21
位 n-2 = 2n-2
位 n-1 = -2n-1
但是当无符号时,位 n-1 的值为 2n-1,因此该数字 2n 太高了。 如果设置了位 n-1,则减去 2n:
def twos_complement(hexstr, bits):
value = int(hexstr, 16)
if value & (1 << (bits - 1)):
value -= 1 << bits
return value
print(twos_complement('FFFE', 16))
print(twos_complement('7FFF', 16))
print(twos_complement('7F', 8))
print(twos_complement('FF', 8))
输出:
-2
32767
127
-1
import struct
对于 Python 3(有注释的帮助):
h = '9DA92DAB'
struct.unpack('>i', bytes.fromhex(h))
对于 Python 2:
h = '9DA92DAB'
struct.unpack('>i', h.decode('hex'))
或者如果是小端:
h = '9DA92DAB'
struct.unpack('<i', h.decode('hex'))
以下是可用于任何大小的十六进制的通用函数:
import math
# hex string to signed integer
def htosi(val):
uintval = int(val,16)
bits = 4 * (len(val) - 2)
if uintval >= math.pow(2,bits-1):
uintval = int(0 - (math.pow(2,bits) - uintval))
return uintval
并使用它:
h = str(hex(-5))
h2 = str(hex(-13589))
x = htosi(h)
x2 = htosi(h2)
这适用于 16 位有符号整数,您可以扩展为 32 位整数。它使用 2 的补码有符号数的基本定义。 另请注意,与 1 的异或与二进制否定相同。
# convert to unsigned
x = int('ffbf', 16) # example (-65)
# check sign bit
if (x & 0x8000) == 0x8000:
# if set, invert and add one to get the negative value, then add the negative sign
x = -( (x ^ 0xffff) + 1)
这是一个很晚的答案,但这里有一个执行上述操作的函数。 这将延伸到您提供的任何长度。 将此部分归功于另一个 SO 答案(我丢失了链接,所以如果您找到它,请提供它)。
def hex_to_signed(source):
"""Convert a string hex value to a signed hexidecimal value.
This assumes that source is the proper length, and the sign bit
is the first bit in the first byte of the correct length.
hex_to_signed("F") should return -1.
hex_to_signed("0F") should return 15.
"""
if not isinstance(source, str):
raise ValueError("string type required")
if 0 == len(source):
raise valueError("string is empty")
sign_bit_mask = 1 << (len(source)*4-1)
other_bits_mask = sign_bit_mask - 1
value = int(source, 16)
return -(value & sign_bit_mask) | (value & other_bits_mask)
bytes.fromhex
: 将字符串转换为字节
所以可以写成:
print(int.from_bytes(bytes.fromhex('9DA92DAB'), signed=True))
输出:
-1649857109