konwersja ciągu bajtów na int (python)

Jak mogę przekonwertować łańcuch bajtów na int w Pythonie?

Powiedz TAK: 'y\xcc\xa6\xbb'

Wymyśliłem sprytny / głupi sposób na zrobienie tego:

sum(ord(c) << (i * 8) for i, c in enumerate('y\xcc\xa6\xbb'[::-1]))

Wiem, że musi być coś wbudowanego lub w standardowej bibliotece, co robi to prościej...

To różni się od konwertowanie ciągu cyfr szesnastkowych, dla których można użyć int (xxx, 16), ale zamiast tego chcę przekonwertować ciąg rzeczywistych wartości bajtów.

Aktualizacja:

Lubię Odpowiedź Jamesa trochę lepsza, ponieważ nie wymaga importowania innego modułu, ale metoda Grega jest szybsza:

>>> from timeit import Timer
>>> Timer('struct.unpack("<L", "y\xcc\xa6\xbb")[0]', 'import struct').timeit()
0.36242198944091797
>>> Timer("int('y\xcc\xa6\xbb'.encode('hex'), 16)").timeit()
1.1432669162750244

Moja metoda hacky:

>>> Timer("sum(ord(c) << (i * 8) for i, c in enumerate('y\xcc\xa6\xbb'[::-1]))").timeit()
2.8819329738616943

DALSZA AKTUALIZACJA:

Ktoś zapytał w komentarzach jaki jest problem z importowaniem innego modułu. Cóż, importowanie modułu niekoniecznie jest tanie, spójrz:

>>> Timer("""import struct\nstruct.unpack(">L", "y\xcc\xa6\xbb")[0]""").timeit()
0.98822188377380371

Uwzględnienie kosztów importowania modułu neguje prawie wszystkie korzyści, jakie ma ta metoda. Wierzę, że obejmie to tylko koszt zaimportowania go raz na cały benchmark; zobacz, co się dzieje, gdy zmuszam go do przeładowania za każdym razem:

>>> Timer("""reload(struct)\nstruct.unpack(">L", "y\xcc\xa6\xbb")[0]""", 'import struct').timeit()
68.474128007888794

Nie trzeba dodawać, że jeśli wykonujesz wiele egzekucji tej metody na jednym imporcie, staje się to proporcjonalnie mniej problemem. Jest to również prawdopodobnie koszt i/o, a nie cpu, więc może zależeć od pojemności i charakterystyki obciążenia konkretnej maszyny.

Author: Community, 2009-01-14

10 answers

Możesz również użyć modułu struct :

>>> struct.unpack("<L", "y\xcc\xa6\xbb")[0]
3148270713L
 87
Author: Greg Hewgill,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-12 13:39:00

W Pythonie 3.2 i nowszych, użyj

>>> int.from_bytes(b'y\xcc\xa6\xbb', byteorder='big')
2043455163

Lub

>>> int.from_bytes(b'y\xcc\xa6\xbb', byteorder='little')
3148270713

Zgodnie z endianness twojego ciągu bajtów.

Działa to również dla liczb całkowitych bajtstringa o dowolnej długości oraz dla liczb całkowitych z dopełnieniem dwóch przez podanie signed=True. Zobacz docs for from_bytes.

 234
Author: Mechanical snail,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-27 12:33:38

Jak powiedział Greg, możesz użyć struct, jeśli masz do czynienia z wartościami binarnymi, ale jeśli masz tylko "liczbę szesnastkową", ale w formacie bajtów, możesz chcieć ją przekonwertować w następujący sposób:

s = 'y\xcc\xa6\xbb'
num = int(s.encode('hex'), 16)

...to jest to samo co:

num = struct.unpack(">L", s)[0]

...tylko, że będzie działać dla dowolnej liczby bajtów.

 61
Author: James Antill,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-14 21:42:52

Używam poniższej funkcji do konwersji danych między int, hex I bajtów.

def bytes2int(str):
 return int(str.encode('hex'), 16)

def bytes2hex(str):
 return '0x'+str.encode('hex')

def int2bytes(i):
 h = int2hex(i)
 return hex2bytes(h)

def int2hex(i):
 return hex(i)

def hex2int(h):
 if len(h) > 1 and h[0:2] == '0x':
  h = h[2:]

 if len(h) % 2:
  h = "0" + h

 return int(h, 16)

def hex2bytes(h):
 if len(h) > 1 and h[0:2] == '0x':
  h = h[2:]

 if len(h) % 2:
  h = "0" + h

 return h.decode('hex')

Źródło: http://opentechnotes.blogspot.com.au/2014/04/convert-values-to-from-integer-hex.html

 7
Author: Jrm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-10 06:35:06
import array
integerValue = array.array("I", 'y\xcc\xa6\xbb')[0]

Ostrzeżenie: powyższe jest ściśle związane z platformą. Zarówno specyfikator "I", jak i endianness konwersji ciągu->int zależą od konkretnej implementacji Pythona. Ale jeśli chcesz przekonwertować wiele liczb całkowitych / ciągów na raz, moduł array robi to szybko.

 6
Author: Rafał Dowgird,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-14 21:55:37

W Pythonie 2.x, można użyć specyfikacji formatu <B dla bajtów niepodpisanych, a <b dla bajtów podpisanych z struct.unpack/struct.pack.

Np:

Niech x = '\xff\x10\x11'

data_ints = struct.unpack('<' + 'B'*len(x), x) # [255, 16, 17]

I:

data_bytes = struct.pack('<' + 'B'*len(data_ints), *data_ints) # '\xff\x10\x11'

to * jest wymagane!

Zobacz https://docs.python.org/2/library/struct.html#format-characters dla listy specyfikacji formatu.

 5
Author: Tetralux,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-07 06:36:01

Int.from_bytes jest najlepszym rozwiązaniem, jeśli jesteś w wersji > = 3.2. "Struct.unpack " rozwiązanie wymaga ciągu znaków, więc nie będzie miało zastosowania do tablic bajtów. Oto inne rozwiązanie:

def bytes2int( tb, order='big'):
    if order == 'big': seq=[0,1,2,3]
    elif order == 'little': seq=[3,2,1,0]
    i = 0
    for j in seq: i = (i<<8)+tb[j]
    return i

Hex( bytes2int( [0x87, 0x65, 0x43, 0x21])) zwraca '0x87654321'.

Obsługuje dużą i małą endianess i jest łatwo modyfikowalny dla 8 bajtów

 1
Author: user3435121,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-25 17:30:35
>>> reduce(lambda s, x: s*256 + x, bytearray("y\xcc\xa6\xbb"))
2043455163

Test 1: odwrotność:

>>> hex(2043455163)
'0x79cca6bb'

Test 2: Liczba bajtów > 8:

>>> reduce(lambda s, x: s*256 + x, bytearray("AAAAAAAAAAAAAAA"))
338822822454978555838225329091068225L

Test 3: przyrost o jeden:

>>> reduce(lambda s, x: s*256 + x, bytearray("AAAAAAAAAAAAAAB"))
338822822454978555838225329091068226L

Test 4: Dodaj jeden bajt, powiedz "A":

>>> reduce(lambda s, x: s*256 + x, bytearray("AAAAAAAAAAAAAABA"))
86738642548474510294585684247313465921L

Test 5: Podziel przez 256:

>>> reduce(lambda s, x: s*256 + x, bytearray("AAAAAAAAAAAAAABA"))/256
338822822454978555838225329091068226L

Wynik jest równy wynikowi testu 4, zgodnie z oczekiwaniami.

 1
Author: user3076105,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-28 16:46:09

Jak wspomniano powyżej, użycie unpack funkcji struct jest dobrym sposobem. Jeśli chcesz zaimplementować własną funkcję, istnieje inne rozwiązanie:

def bytes_to_int(bytes):
    result = 0
    for b in bytes:
        result = result * 256 + int(b)
return result
 1
Author: abdullahselek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-27 09:34:47

Starałem się znaleźć rozwiązanie dla sekwencji bajtów o dowolnej długości, które działałyby pod Pythonem 2.x. W końcu napisałem ten, jest trochę chwiejny, ponieważ wykonuje konwersję strun, ale działa.

Funkcja dla Pythona 2.x, dowolna długość

def signedbytes(data):
    """Convert a bytearray into an integer, considering the first bit as
    sign. The data must be big-endian."""
    negative = data[0] & 0x80 > 0

    if negative:
        inverted = bytearray(~d % 256 for d in data)
        return -signedbytes(inverted) - 1

    encoded = str(data).encode('hex')
    return int(encoded, 16)

Ta funkcja ma dwa wymagania:

  • Wejście data musi być bytearray. Możesz wywołać funkcję w następujący sposób:

    s = 'y\xcc\xa6\xbb'
    n = signedbytes(s)
    
  • Dane muszą być big-endian. Jeśli masz wartość trochę endyjska, powinieneś ją najpierw odwrócić:

    n = signedbytes(s[::-1])
    

Oczywiście, powinna być używana tylko wtedy, gdy potrzebna jest dowolna długość. W przeciwnym razie trzymaj się bardziej standardowych sposobów (np. struct).

 0
Author: Andrea Lazzarotto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-07 17:36:08