Який правильний спосіб перетворити байти в шістнадцяткову рядок в Python 3?


235

Який правильний спосіб перетворити байти в шістнадцяткову рядок в Python 3?

Я бачу твердження bytes.hexметоду, bytes.decodeкодеків і безрезультатно спробував інші можливі функції, щонайменше, здивування. Я просто хочу, щоб мої байти були шістнадцятковими!


"безрезультатно"? Які конкретні проблеми чи помилки ви отримуєте? Будь ласка, покажіть код та помилки.
S.Lott

Відповіді:


409

З Python 3.5, нарешті, це вже не незручно:

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

і назад:

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

працює також із мутаційним bytearrayтипом.

Довідка: https://docs.python.org/3/library/stdtypes.html#bytes.hex


5
bytes.fromhex()також доступний на Python 3.0+ (не лише 3.5+). bytes.hex()є лише на Python 3.5+.
фенікс

95

Використовуйте binasciiмодуль:

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

Дивіться цю відповідь: Рядок Python 3.1.1 в шістнадцятковий


8
Це добре. Боротьба з розумом полягає в тому, що ви можете перетворити hex в байти за допомогою bytes.fromhex (hex_str), але ви не можете перетворити байти в hex за допомогою bytes.tohex () - що в цьому раціональне?
nagylzs

1
Я думаю, що зв'язок між байтами та hex не є властивістю жодного (що не відповідає, чому з hex існує). Здається, це був не просто нагляд, а щось, про що сперечалися: bugs.python.org/issue3532#msg70950 . Питання: Чи не завадить метод tohex об'єкта bytes для виконання цього завдання? A: ІМО, так, було б. Це ускладнює код і відводить фокус від правильного підходу до перетворення даних (а саме функції - не методи).
Mu Mind

3
Це справді відповідає на питання? Він не повертає шістнадцятковий, strа а bytes. Я знаю, що ОП здається задоволеною відповіддю, але не буде кращого розширити цю відповідь, щоб вона .decode("ascii")також перетворила її на "рядок"
RubenLaguna

3
Я думав, що багато людей приземляються на це питання / відповідь, шукаючи спосіб роздрукувати bytes. Якщо ви print(b'666f6f')потрапляєте bу роздруківку. Якщо ти, .decode("ascii")то не робиш. Думаючи лише про те, як ті, хто насправді мав bytes(справжній бінарний файл з елементами> 128, а не рядок ascii), хотіли роздрукувати його.
RubenLaguna

5
@nagylzs: існує .hex()метод у Python 3.5+
jfs

43

У Python є стандартні кодеки від байтів до байтів, які виконують зручні перетворення, такі як друковані з цитатами (вписуються в 7-бітну ascii), base64 (вписуються в буквено-цифрові символи), шістнадцяткове втечання, стискання gzip та bz2. У Python 2 ви можете:

b'foo'.encode('hex')

У Python 3 str.encode/ / bytes.decodeсуворо для байтів <-> перетворення рядків. Натомість ви можете зробити це, що працює через Python 2 та Python 3 ( s / encode / decode / g для зворотного):

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

Починаючи з Python 3.4, є менш незручний варіант:

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

Ці різни кодеки також доступні всередині власних модулів (base64, zlib, bz2, uu, quopri, binascii); API менш стійкий, але для кодеків стиснення він пропонує більше контролю.


1
використовуючи python 3.3:LookupError: unknown encoding: hex
Janus Troelsen

@JanusTroelsen: спробуйте "hex_codec" . Або просто скористайтеся binascii.hexlify(b'foo')безпосередньо
jfs


6

Метод binascii.hexlify()перетвориться bytesна bytesпредставляючу шістнадцяткову рядок ascii. Це означає, що кожен байт у введенні буде перетворений на два символи ascii. Якщо ви хочете справжнього str, тоді ви можете .decode("ascii")отримати результат.

Я включив фрагмент, який це ілюструє.

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

з шістнадцяткової рядка "0a160a04"до може повернутися до того, bytesз binascii.unhexlify("0a160a04")яким повертаєтьсяb'\n\x16\n\x04'


3

Гаразд, наступна відповідь трохи виходить за рамки, якщо вас цікавить лише Python 3, але це питання є першим зверненням Google, навіть якщо ви не вказали версію Python, тож ось спосіб, який працює і на Python 2, і на Python 3 .

Я також інтерпретую питання про перетворення байтів у strтип: тобто байт-y на Python 2, і Unicode-y на Python 3.

З огляду на це, найкращий мене підхід:

import six

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

Наступне твердження буде справедливим або для Python 2, або для Python 3, якщо ви не активували unicode_literalsмайбутнє в Python 2:

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

(Або ви можете ''.join()опустити простір між байтами тощо)


3

може використовуватися специфікатор %x02формату цього формату і виводити шістнадцяткове значення. Наприклад:

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

На мою думку, це найкраща відповідь, оскільки він працює з кожною версією Python і не потребує жодного імпорту. І все ж, я б краще відображав шістнадцяткові рядки у верхньому регістріres.upper()
Бруно Л.,


0

Якщо ви хочете перетворити b '\ x61' в 97 або '0x61', ви можете спробувати це:

[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'

Довідка: https://docs.python.org/3.5/library/struct.html


Якось мені допомагає esp32
Tejas Tank
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.