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!


„bez pomocy”? Jakie masz konkretne problemy lub błędy? Pokaż kod i błędy.
S.Lott,

Odpowiedzi:



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ę


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ę.


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”).


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'


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


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

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.


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


Jakoś pomaga mi z esp32
Tejas Tank
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.