2011-07-18 13 views
11

Jak przekonwertować ciąg szesnastkowy na podpisane int w Pythonie 3.2?Łańcuch szesnastkowy do podpisu int w Pythonie 3.2?

Najlepszym mogę wymyślić jest

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

Czy istnieje prostszy sposób? Unsigned jest dużo łatwiejsze: int (H, 16)

BTW, pochodzenie tej kwestii jest itunes persistent id - music library xml version and iTunes hex version

+0

Dwie linie b = i ba = można zastąpić bajtami ba = bajtów.fromheks (h). Zobacz komentarz Lennarta poniżej. – foosion

Odpowiedz

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

Wierzę, że klauzula if wymaga x = -x na końcu – foosion

+2

Dobrze, nienawidzę pisania kodu na iPadzie. Nie można go uruchomić, aby sprawdzić dwukrotnie. –

+0

Pamiętaj o tym bez uruchamiania go (lub o lepszych umiejętnościach od Google niż ja) jest dobry – foosion

4
import struct 

dla Pythona 3 (z pomocą Uwagi):

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

dla Pythona 2:

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

lub jeśli jest to mały endian:

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

Działa w python 2.7, ale nie 3.2: AttributeError: obiekt 'str' nie ma atrybutu 'dekodowanie' – foosion

+1

Nie używaj Pythona 3 do testowania tego włączone, ale oparte na dokumentacji 'struct.unpack ('> i', bytes ('9DA92DAB', 'utf-8')) powinno działać. – kichik

+2

Nie ma. h.decode ("hex") i bajty (h, "utf8") robią zupełnie różne rzeczy. Chcesz bytes.fromhex (h). –

1

Oto ogólny funkcji można użyć do hex każdej wielkości:

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 

I z niego korzystać:

h = str(hex(-5)) 
h2 = str(hex(-13589)) 
x = htosi(h) 
x2 = htosi(h2) 
0

Działa to dla 16 bitowe podpisane int, można rozszerzyć na 32-bitowe ints. Używa podstawowej definicji 2's complement signed numbers. Zauważ także, że xor z 1 jest taki sam jak binarna negacja.

# 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) 
0

To bardzo spóźniona odpowiedź, ale oto funkcja do wykonania powyższych czynności. Rozciągnie się to na dowolną długość, którą zapewnisz. Zaliczenie części tego na inną odpowiedź SO (straciłem link, więc proszę podać go, jeśli go znajdziesz).

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) 
Powiązane problemy