Шестнадцатеричная строка для подписанного int в Python 3.2?

Как преобразовать шестнадцатеричную строку в подписанный int в Python 3.2?

Лучшее, что я могу придумать, -

h = '9DA92DAB'
b = bytes(h, 'utf-8')
ba = binascii.a2b_hex(b)
print(int.from_bytes(ba, byteorder='big', signed=True))

Есть ли более простой способ? Unsigned намного проще: int (h, 16)

Кстати, источником вопроса является itunes persistent id - музыкальная библиотека xml-версия и версия iTunes hex

Ответ 1

x = int(h,16)
if x > 0x7FFFFFFF:
    x -= 0x100000000

Ответ 2

import struct

Для Python 3 (с помощью комментариев):

h = '9DA92DAB'
struct.unpack('>i', bytes.fromhex(h))

Для Python 2:

h = '9DA92DAB'
struct.unpack('>i', h.decode('hex'))

или если это немного endian:

h = '9DA92DAB'
struct.unpack('<i', h.decode('hex'))

Ответ 3

Здесь общая функция, которую вы можете использовать для 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)

Ответ 4

Это работает для 16-битных подписных int, вы можете расширить для 32-битных int. Он использует базовое определение 2 дополняемых числа. Также обратите внимание, что 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)