在Python 3.2中使用signed string的十六进制字符串?

时间:2011-07-18 01:16:49

标签: integer python-3.x hex

如何在Python 3.2中将十六进制字符串转换为signed int?

我能想到的最好的是

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 persistent id - music library xml version and iTunes hex version

5 个答案:

答案 0 :(得分:31)

在n位二进制补码中,位具有值:

  

位0 = 2 0
  bit 1 = 2 1
  位n-2 = 2 n-2
  位n-1 = -2 n-1

但是当无符号时,位n-1的值为2 n-1 ,因此该数字为2 n 太高。如果设置了位n-1,则减去2 n

>>> def twos_complement(hexstr,bits):
...     value = int(hexstr,16)
...     if value & (1 << (bits-1)):
...         value -= 1 << bits
...     return value
...
>>> twos_complement('FFFE',16)
-2
>>> twos_complement('7FFF',16)
32767
>>> twos_complement('7F',8)
127
>>> twos_complement('FF',8)
-1

答案 1 :(得分:5)

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'))

答案 2 :(得分:1)

这是一个可以用于任何大小的十六进制的通用函数:

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)

答案 3 :(得分:1)

这适用于16位有符号整数,可以扩展为32位整数。它使用2's complement signed numbers.的基本定义。另请注意,xor with 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)

答案 4 :(得分: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)