Jaki jest prawidłowy sposób konwersji bajtów na ciąg szesnastkowy w Pythonie 3?

235

Jaki jest prawidłowy sposób konwersji bajtów na ciąg szesnastkowy w Pythonie 3?

Widzę roszczenia do bytes.hexmetody, bytes.decodekodeków i wypróbowałem inne możliwe funkcje najmniejszego zdziwienia bezskutecznie. Chcę tylko moje bajty jako hex!

Matt Joiner
źródło
„bez pomocy”? Jakie masz konkretne problemy lub błędy? Pokaż kod i błędy.
S.Lott,

Odpowiedzi:

409

Od wersji Python 3.5 nie jest to już niewygodne:

>>> b'\xde\xad\xbe\xef'.hex()
'deadbeef'

i odwróć:

>>> bytes.fromhex('deadbeef')
b'\xde\xad\xbe\xef'

działa również z bytearraytypem zmiennym .

Odniesienie: https://docs.python.org/3/library/stdtypes.html#bytes.hex

Felix Weis
źródło
5
bytes.fromhex()jest również dostępny w Python 3.0+ (nie tylko 3.5+). bytes.hex()jest tylko w Python 3.5+.
feniks
95

Użyj binasciimodułu:

>>> import binascii
>>> binascii.hexlify('foo'.encode('utf8'))
b'666f6f'
>>> binascii.unhexlify(_).decode('utf8')
'foo'

Zobacz następującą odpowiedź: Ciąg w Pythonie 3.1.1 na szesnastkę

Mu Mind
źródło
8
To jest dobre. Zadziwiające jest to, że możesz przekonwertować hex na bajty za pomocą bytes.fromhex (hex_str), ale nie możesz przekonwertować bajtów na hex za pomocą bytes.tohex () - co jest w tym sensownego?
nagylzs
1
Myślę, że związek między bajtami a heksadecymalnym nie jest własnością żadnego z nich (co nie odpowiada, dlaczego fromhex tam jest). Wygląda na to, że nie był to tylko przeoczenie, ale coś, o co dyskutowano: bugs.python.org/issue3532#msg70950 . P: Czy szkoda byłoby, gdyby metoda tohex obiektu bajtów również wykonywała to zadanie? Odp .: IMO, tak. Komplikuje kod i odwraca uwagę od właściwego podejścia do konwersji danych (a mianowicie funkcji - nie metod).
Mu Mind
3
Czy to naprawdę odpowiada na pytanie? Nie zwraca heksa, strale bytes. Wiem, że OP wydaje się być zadowolony z odpowiedzi, ale nie będzie lepiej rozszerzyć tę odpowiedź, aby objąć .decode("ascii")ją również „ciągiem”
RubenLaguna
3
Myślałem, że wiele osób trafia na to pytanie / odpowiedź, szukając sposobu na wydruk bytes. Jeśli print(b'666f6f')dostaniesz bna wydruku. Jeśli nie .decode("ascii"), to nie. Wystarczy pomyśleć o tym, jak ci, którzy faktycznie mieli bytes(prawdziwy plik binarny z elementami> 128, a nie ciąg ascii), chcieli go wydrukować.
RubenLaguna,
5
@nagylzs: .hex()w Python 3.5+ istnieje metoda
jfs
43

Python ma standardowe kodeki bajt-bajt, które wykonują wygodne transformacje, takie jak drukowanie w cudzysłowie (pasuje do 7-bitowych znaków ascii), base64 (pasuje do znaków alfanumerycznych), ucieczkę szesnastkową, kompresję gzip i bz2. W Pythonie 2 możesz wykonać:

b'foo'.encode('hex')

W Pythonie 3, str.encode/ bytes.decodesą przeznaczone wyłącznie do konwersji bajtów <-> str. Zamiast tego możesz to zrobić, co działa w Pythonie 2 i Pythonie 3 ( s / encode / decode / g dla odwrotności):

import codecs
codecs.getencoder('hex')(b'foo')[0]

Począwszy od Python 3.4, jest mniej niewygodna opcja:

codecs.encode(b'foo', 'hex')

Te różne kodeki są również dostępne we własnych modułach (base64, zlib, bz2, uu, quopri, binascii); interfejs API jest mniej spójny, ale w przypadku kodeków kompresji oferuje większą kontrolę.

Gabriel
źródło
1
używając Pythona 3.3:LookupError: unknown encoding: hex
Janus Troelsen
@JanusTroelsen: spróbuj „hex_codec” . Lub użyj binascii.hexlify(b'foo')bezpośrednio
jfs
7
import codecs
codecs.getencoder('hex_codec')(b'foo')[0]

działa w Pythonie 3.3 (więc „hex_codec” zamiast „hex”).

Richard Kiss
źródło
Być może co ciekawe, w Pythonie 3.4 „hex” lub „hex_codec” działa dobrze.
Stephen Paulger
6

Metoda binascii.hexlify()zostanie przekonwertowana bytesna bytesreprezentujący ciąg szesnastkowy ascii. Oznacza to, że każdy bajt na wejściu zostanie przekonwertowany na dwa znaki ascii. Jeśli chcesz się spełnić str, możesz uzyskać .decode("ascii")wynik.

Dołączyłem fragment, który to ilustruje.

import binascii

with open("addressbook.bin", "rb") as f: # or any binary file like '/bin/ls'
    in_bytes = f.read()
    print(in_bytes) # b'\n\x16\n\x04'
    hex_bytes = binascii.hexlify(in_bytes) 
    print(hex_bytes) # b'0a160a04' which is twice as long as in_bytes
    hex_str = hex_bytes.decode("ascii")
    print(hex_str) # 0a160a04

z ciągiem szesnastkowym "0a160a04", aby można wrócić do bytesz binascii.unhexlify("0a160a04")której oddajeb'\n\x16\n\x04'

RubenLaguna
źródło
3

OK, poniższa odpowiedź jest nieco poza zakresem, jeśli dbasz tylko o Python 3, ale to pytanie jest pierwszym hitem Google, nawet jeśli nie określisz wersji Python, więc oto sposób, który działa zarówno na Python 2, jak i Python 3 .

Interpretuję również pytanie o konwersję bajtów na strtyp: to znaczy bajty-y w Pythonie 2 i Unicode-y w Pythonie 3.

Biorąc to pod uwagę, najlepszym znanym mi podejściem jest:

import six

bytes_to_hex_str = lambda b: ' '.join('%02x' % i for i in six.iterbytes(b))

Poniższe stwierdzenie będzie prawdziwe dla Pythona 2 lub Pythona 3, zakładając, że nie aktywowałeś unicode_literalsprzyszłości w Pythonie 2:

assert bytes_to_hex_str(b'jkl') == '6a 6b 6c'

(Lub możesz użyć, ''.join()aby pominąć spację między bajtami itp.)

Piotr
źródło
3

można użyć specyfikatora formatu, %x02który formatuje i generuje wartość szesnastkową. Na przykład:

>>> foo = b"tC\xfc}\x05i\x8d\x86\x05\xa5\xb4\xd3]Vd\x9cZ\x92~'6"
>>> res = ""
>>> for b in foo:
...     res += "%02x" % b
... 
>>> print(res)
7443fc7d05698d8605a5b4d35d56649c5a927e2736
Arg0s
źródło
Według mnie jest to najlepsza odpowiedź, ponieważ działa z każdą wersją Pythona i nie wymaga żadnego importu. Lepiej jednak wyświetlać ciągi szesnastkowe dużymi literamires.upper()
Bruno L.
3

Nowość w Pythonie 3.8, możesz przekazać argument hexfunkcji ogranicznika, tak jak w tym przykładzie

>>> value = b'\xf0\xf1\xf2'
>>> value.hex('-')
'f0-f1-f2'
>>> value.hex('_', 2)
'f0_f1f2'
>>> b'UUDDLRLRAB'.hex(' ', -4)
'55554444 4c524c52 4142'

https://docs.python.org/3/library/stdtypes.html#bytes.hex

Peter Mitrano
źródło
0

Jeśli chcesz przekonwertować b '\ x61' na 97 lub „0x61”, możesz spróbować:

[python3.5]
>>>from struct import *
>>>temp=unpack('B',b'\x61')[0] ## convert bytes to unsigned int
97
>>>hex(temp) ##convert int to string which is hexadecimal expression
'0x61'

Odniesienie: https://docs.python.org/3.5/library/struct.html

hao li
źródło
Jakoś pomaga mi z esp32
Tejas Tank