【问题标题】:Hex string to signed int in Python 3.2?十六进制字符串到 Python 3.2 中的带符号整数?
【发布时间】:2011-10-07 08:36:10
【问题描述】:

如何在 Python 3.2 中将十六进制字符串转换为有符号整数?

我能想到的最好的是

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

【问题讨论】:

  • 这两行 b= 和 ba= 可以用 ba=bytes.fromhex(h) 代替。请参阅下面 Lennart 的评论。

标签: integer python-3.x hex


【解决方案1】:

在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
...
>>> twos_complement('FFFE',16)
-2
>>> twos_complement('7FFF',16)
32767
>>> twos_complement('7F',8)
127
>>> twos_complement('FF',8)
-1

【讨论】:

  • bits = hexstr.__len__() 所以没有必要将位作为参数传入。除非,例如,您希望 hexstr = 'FF' 表示 32 位值。
  • @DeanM 我假设你的意思是len(hexstr) * 4,是的,这个数字可能缺少前导零,所以我明确说明了答案中的位数。
【解决方案2】:
import struct

对于 Python 3(在 cmets 的帮助下):

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

【讨论】:

    【解决方案3】:

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

    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)
    

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

        这是一个很晚的答案,但这里有一个功能可以完成上述操作。这将扩展到您提供的任何长度。将此部分归功于另一个 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)
        

        【讨论】:

          猜你喜欢
          • 2021-03-07
          • 2013-09-06
          • 2013-04-28
          • 2018-08-04
          • 2014-10-19
          • 2017-08-07
          • 1970-01-01
          • 2017-02-28
          • 2013-08-05
          相关资源
          最近更新 更多