Quelle est la bonne façon de convertir des octets en une chaîne hexadécimale en Python 3?

236

Quelle est la bonne façon de convertir des octets en une chaîne hexadécimale en Python 3?

Je vois des revendications d'une bytes.hexméthode, des bytes.decodecodecs, et j'ai essayé d' autres fonctions possibles du moindre étonnement en vain. Je veux juste mes octets en hexadécimal!

Matt Joiner
la source
"sans résultat"? Quels problèmes ou erreurs spécifiques rencontrez-vous? Veuillez afficher le code et les erreurs.
S.Lott

Réponses:

410

Depuis Python 3.5, ce n'est finalement plus gênant:

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

et inverser:

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

fonctionne également avec le bytearraytype mutable .

Référence: https://docs.python.org/3/library/stdtypes.html#bytes.hex

Felix Weis
la source
5
bytes.fromhex()est également disponible sur Python 3.0+ (et pas seulement 3.5+). bytes.hex()est uniquement sur Python 3.5+.
phoenix
95

Utilisez le binasciimodule:

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

Voir cette réponse: chaîne Python 3.1.1 en hexadécimal

Mu Mind
la source
8
C'est bon. C'est ahurissant que vous pouvez convertir des hex en octets en utilisant bytes.fromhex (hex_str), mais vous ne pouvez pas convertir des octets en hex en utilisant bytes.tohex () - quel est le rationnel dans tout cela?
nagylzs
1
Je suppose que la relation entre octets et hexadécimal n'est pas une propriété non plus (ce qui ne répond pas pourquoi fromhex est là). Il semble que ce ne soit pas seulement un oubli mais quelque chose qui a été débattu : bugs.python.org/issue3532#msg70950 . Q: Serait-il gênant d'avoir la méthode tohex de l'objet bytes pour effectuer cette tâche également? R: IMO, oui, ce serait le cas. Cela complique le code et détourne l'attention de la bonne approche de la conversion des données (à savoir les fonctions - pas les méthodes).
Mu Mind
3
Est-ce que cela répond vraiment à la question? Il ne renvoie pas un hex strmais un bytes. Je sais que l'OP semble satisfait de la réponse mais ne sera pas mieux d'étendre cette réponse pour l'inclure .decode("ascii")également pour la convertir en "chaîne"
RubenLaguna
3
Je pensais que beaucoup de gens atterrissent sur cette question / réponse à la recherche d'un moyen d'imprimer a bytes. Si vous print(b'666f6f')obtenez le bdans l'impression. Si vous .decode("ascii")ne le faites pas. Je pensais juste à la façon dont ceux qui avaient réellement un bytes(vrai binaire avec des éléments> 128, pas une chaîne ascii) voulaient l'imprimer.
RubenLaguna
5
@nagylzs: il existe une .hex()méthode en Python 3.5+
jfs
43

Python a des codecs standard octets à octets qui effectuent des transformations pratiques comme les citations imprimables (s'adapte en 7 bits ascii), base64 (s'adapte en alphanumériques), l'échappement hexadécimal, la compression gzip et bz2. En Python 2, vous pourriez faire:

b'foo'.encode('hex')

En Python 3, str.encode/ bytes.decodesont strictement réservés aux conversions d'octets <-> str. Au lieu de cela, vous pouvez le faire, ce qui fonctionne sur Python 2 et Python 3 ( s / encode / decode / g pour l'inverse):

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

À partir de Python 3.4, il existe une option moins gênante:

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

Ces codecs divers sont également accessibles à l'intérieur de leurs propres modules (base64, zlib, bz2, uu, quopri, binascii); l'API est moins cohérente, mais pour les codecs de compression, elle offre plus de contrôle.

Gabriel
la source
1
en utilisant python 3.3:LookupError: unknown encoding: hex
Janus Troelsen
@JanusTroelsen: essayez 'hex_codec' . Ou utilisez binascii.hexlify(b'foo')directement
jfs
7
import codecs
codecs.getencoder('hex_codec')(b'foo')[0]

fonctionne en Python 3.3 (donc "hex_codec" au lieu de "hex").

Richard Kiss
la source
Peut-être intéressant de noter qu'en Python 3.4, "hex" ou "hex_codec" fonctionne très bien.
Stephen Paulger
6

La méthode binascii.hexlify()sera convertie bytesen un bytesreprésentant la chaîne hexadécimale ascii. Cela signifie que chaque octet dans l'entrée sera converti en deux caractères ascii. Si vous voulez une vraie strsortie, vous pouvez .decode("ascii")le résultat.

J'ai inclus un extrait qui l'illustre.

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

de la chaîne hexagonale "0a160a04"à peut revenir à la bytesavec ce binascii.unhexlify("0a160a04")qui donne de retourb'\n\x16\n\x04'

RubenLaguna
la source
3

OK, la réponse suivante est légèrement hors de portée si vous ne vous souciez que de Python 3, mais cette question est le premier hit de Google même si vous ne spécifiez pas la version Python, alors voici une méthode qui fonctionne à la fois sur Python 2 et Python 3 .

J'interprète également la question de la conversion d'octets en strtype: autrement dit, octets-y sur Python 2 et Unicode-y sur Python 3.

Compte tenu de cela, la meilleure approche que je connaisse est:

import six

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

L'affirmation suivante sera vraie pour Python 2 ou Python 3, en supposant que vous n'avez pas activé l' unicode_literalsavenir dans Python 2:

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

(Ou vous pouvez utiliser ''.join()pour omettre l'espace entre les octets, etc.)

Peter
la source
3

il peut être utilisé le spécificateur de %x02format qui formate et génère une valeur hexadécimale. Par exemple:

>>> 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
la source
Selon moi, c'est la meilleure réponse car elle fonctionne avec toutes les versions de Python et ne nécessite aucune importation. Pourtant, je ferais mieux d'afficher des chaînes hexa en majusculesres.upper()
Bruno L.
3

Nouveau dans python 3.8, vous pouvez passer un argument délimiteur à la hexfonction, comme dans cet exemple

>>> 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
la source
0

Si vous voulez convertir b '\ x61' en 97 ou '0x61', vous pouvez essayer ceci:

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

Référence: https://docs.python.org/3.5/library/struct.html

hao li
la source
D'une certaine manière m'aide avec esp32
Tejas Tank