Eine Zeichenfolge als Hex-Bytes drucken?


155

Ich habe diese Zeichenfolge: Hello world !!und ich möchte sie mit Python als drucken 48:65:6c:6c:6f:20:77:6f:72:6c:64:20:21:21.

hex() funktioniert nur für ganze Zahlen.

Wie geht das?


Wenn nur zweistellige Hex-Werte zurückgegeben werden sollen, impliziert diese Frage die Verwendung von Byte- Strings (dh Python 2 stroder Python 3 bytestring), da in 0… 255 keine eindeutige Umwandlung eines Zeichens in eine Ganzzahl erfolgt. Daher erfordern Zeichenketten (Python 2 unicodeund Python 3 str) zunächst eine gewisse Codierung, bevor sie in dieses hexadezimale Format konvertiert werden können. Die Antwort von Aaron Hall veranschaulicht dies.
Eric O Lebigot

Antworten:


227

Sie können Ihre Zeichenfolge in einen Int-Generator umwandeln, für jedes Element eine Hex-Formatierung anwenden und mit einem Trennzeichen interkalieren:

>>> s = "Hello world !!"
>>> ":".join("{:02x}".format(ord(c)) for c in s)
'48:65:6c:6c:6f:20:77:6f:72:6c:64:20:21:21

3
Beachten Sie, dass in Python3 das Konzept des Druckens eines strals Hex nicht wirklich sinnvoll ist. Sie drucken möchten bytesObjekt als hex (convert strzu bytesdurch den Aufruf .encode()).
mic_e

8
Tatsächlich erzeugt diese ungültige Ausgabe in python3: ":".join("{:02x}".format(ord(c)) for c in 'løl')Renditen '6c:f8:6c', während ":".join("{:02x}".format(c) for c in 'løl'.encode())die Darstellung korrekt utf-8 erzeugt '6c:c3:b8:6c'.
mic_e

2
Bei dieser Frage und Antwort wird davon ausgegangen, dass Ihre Eingabe niemals Nicht-ASCII-Zeichen enthält. Wenn Ihre Eingabe möglicherweise Dinge wie Emojis oder nicht auf Latein basierende Schriftsysteme enthält, möchten Sie möglicherweise stattdessen ":".join("{:04x}".format(ord(c)) for c in s)(Ersetzen 02xdurch 04xdurch Nullstellen jeder Zahl mit 4 Ziffern) verwenden
Boris

157
':'.join(x.encode('hex') for x in 'Hello World!')

3
Wie mache ich das in Python3?
h__

6
@hyh: nach jeweils zwei hexadezimalen Ziffern h = binascii.hexlify(b"Hello world !!") to get hex string. b":".join(h[i:i+2] for i in range(0, len(h), 2))einfügen ':'.
JFS

2
Funktioniert nicht auf Python 3.LookupError: 'hex' is not a text encoding; use codecs.encode() to handle arbitrary codecs
Boris

55

Für Python 2.x:

':'.join(x.encode('hex') for x in 'Hello World!')

Der obige Code funktioniert nicht mit Python 3.x , für 3.x funktioniert der folgende Code:

':'.join(hex(ord(x))[2:] for x in 'Hello World!')

1
Es sollte auch beachtet werden, dass das letztere AUCH mit python2.x funktioniert UND es auch für Nicht-ASCII-Zeichen
funktioniert

1
Beachten Sie aber auch, dass letzteres keine führenden Nullen auffüllt: hex (ord ("\ x00")) [2:] ist "0" und "\ x00" .encode ("hex") == "00"
Will Daniels

3
Warum haben Sie sich entschieden, dies als neue Antwort zu veröffentlichen, Monate nachdem beide Lösungen von anderen Benutzern angeboten wurden? Wenn es darum ging, die Versionskompatibilität zu klären, wäre es sinnvoller gewesen, Änderungen an den vorhandenen Antworten vorzuschlagen.
Air

2
Wie an anderer Stelle erwähnt, ist diese Antwort nicht einmal richtig, wenn man sich über ASCII hinausbewegt und Unicode berücksichtigt. ':'. join (hex (ord (x)) [2:] für x in 'løl') gibt '6c: f8: 6c' falsch aus, während die korrekte Ausgabe '6c: c3: b8: 6c' ist.
Mcduffee

23

Eine weitere Antwort in zwei Zeilen, die für manche möglicherweise leichter zu lesen ist und beim Debuggen von Zeilenumbrüchen oder anderen ungeraden Zeichen in einer Zeichenfolge hilfreich ist:

Für Python 2.7

for character in string:
    print character, character.encode('hex')

Für Python 3.7 (nicht in allen Versionen von 3 getestet)

for character in string:
    print(character, character.encode('utf-8').hex())

Dies funktioniert ab Python 3.6.8 (zumindest) nicht mehr: "hex" ist keine Codierung von Zeichenfolgen. codecs.encode(<bytestring>, "hex")funktioniert aber.
Eric O Lebigot

2
Ah, schön danke für die Info ... ja das wurde definitiv für Python 2.7 geschrieben. Ich werde meine Antwort aktualisieren, um zu zeigen, wie es für Python 3.7 geht.
Copeland3300

Verifiziert, Python 3.7.6 : import sys; s="Déjà vu Besançon,Lupiñén,Šiauliai,Großräschen,Łódź,Аша,广东省,LA";; for c in s:;; w=sys.stdout.write(c+":"+c.encode('utf-8').hex()+"||");; (out)D:44||é:c3a9||j:6a||à:c3a0|| :20||v:76||u:75|| :20||B:42||e:65||s:73||a:61||n:6e||ç:c3a7||o:6f||n:6e||,:2c||L:4c||u:75||p:70||i:69||ñ:c3b1||é:c3a9||n:6e||,:2c||Š:c5a0||i:69||a:61||u:75||l:6c||i:69||a:61||i:69||,:2c||G:47||r:72||o:6f||ß:c39f||r:72||ä:c3a4||s:73||c:63||h:68||e:65||n:6e||,:2c||Ł:c581||ó:c3b3||d:64||ź:c5ba||,:2c||А:d090||ш:d188||а:d0b0||,:2c||广:e5b9bf||东:e4b89c||省:e79c81||,:2c||L:4c||A:41||
bballdave025

20

Einige Ergänzungen zu Fedor Gogolev antworten:

Erstens, wenn die Zeichenfolge Zeichen enthält, deren 'ASCII-Code' unter 10 liegt, werden sie nicht wie erforderlich angezeigt. In diesem Fall sollte das richtige Format sein {:02x}:

>>> s = "Hello unicode \u0005 !!"
>>> ":".join("{0:x}".format(ord(c)) for c in s)
'48:65:6c:6c:6f:20:75:6e:69:63:6f:64:65:20:5:20:21:21'
                                           ^

>>> ":".join("{:02x}".format(ord(c)) for c in s)
'48:65:6c:6c:6f:20:75:6e:69:63:6f:64:65:20:05:20:21:21'
                                           ^^

Zweitens, wenn Ihre "Zeichenfolge" in Wirklichkeit eine "Byte-Zeichenfolge" ist - und da der Unterschied in Python 3 von Bedeutung ist -, bevorzugen Sie möglicherweise Folgendes:

>>> s = b"Hello bytes \x05 !!"
>>> ":".join("{:02x}".format(c) for c in s)
'48:65:6c:6c:6f:20:62:79:74:65:73:20:05:20:21:21'

Bitte beachten Sie, dass im obigen Code keine Konvertierung erforderlich ist, da ein Byte-Objekt als "unveränderliche Folge von Ganzzahlen im Bereich 0 <= x <256" definiert ist .


11

Eine Zeichenfolge als Hex-Bytes drucken?

Die akzeptierte Antwort lautet:

s = "Hello world !!"
":".join("{:02x}".format(ord(c)) for c in s)

kehrt zurück:

'48:65:6c:6c:6f:20:77:6f:72:6c:64:20:21:21'

Die akzeptierte Antwort funktioniert nur, solange Sie Bytes (meistens ASCII-Zeichen) verwenden. Wenn Sie jedoch Unicode verwenden, z.

a_string = u"Привет мир!!" # "Prevyet mir", or "Hello World" in Russian.

Sie müssen irgendwie in Bytes konvertieren.

Wenn Ihr Terminal diese Zeichen nicht akzeptiert, können Sie UTF-8 dekodieren oder die Namen verwenden (damit Sie den Code zusammen mit mir einfügen und ausführen können):

a_string = (
    "\N{CYRILLIC CAPITAL LETTER PE}"
    "\N{CYRILLIC SMALL LETTER ER}"
    "\N{CYRILLIC SMALL LETTER I}"
    "\N{CYRILLIC SMALL LETTER VE}"
    "\N{CYRILLIC SMALL LETTER IE}"
    "\N{CYRILLIC SMALL LETTER TE}"
    "\N{SPACE}"
    "\N{CYRILLIC SMALL LETTER EM}"
    "\N{CYRILLIC SMALL LETTER I}"
    "\N{CYRILLIC SMALL LETTER ER}"
    "\N{EXCLAMATION MARK}"
    "\N{EXCLAMATION MARK}"
)

Also sehen wir das:

":".join("{:02x}".format(ord(c)) for c in a_string)

kehrt zurück

'41f:440:438:432:435:442:20:43c:438:440:21:21'

Ein schlechtes / unerwartetes Ergebnis - dies sind die Codepunkte , die zusammen die in Unicode angezeigten Grapheme des Unicode-Konsortiums ergeben, die Sprachen auf der ganzen Welt repräsentieren. Dies ist nicht , wie wir diese Informationen tatsächlich gespeichert werden, so dass es durch andere Quellen interpretiert werden kann, though.

Damit eine andere Quelle diese Daten verwenden kann, müssen wir normalerweise in UTF-8-Codierung konvertieren, um diese Zeichenfolge beispielsweise in Byte auf der Festplatte zu speichern oder in HTML zu veröffentlichen. Daher benötigen wir diese Codierung, um die Codepunkte in die Codeeinheiten von UTF-8 zu konvertieren - in Python 3 ordwird sie nicht benötigt, da byteses sich um iterierbare Ganzzahlen handelt:

>>> ":".join("{:02x}".format(c) for c in a_string.encode('utf-8'))
'd0:9f:d1:80:d0:b8:d0:b2:d0:b5:d1:82:20:d0:bc:d0:b8:d1:80:21:21'

Oder vielleicht eleganter mit den neuen F-Strings (nur in Python 3 verfügbar):

>>> ":".join(f'{c:02x}' for c in a_string.encode('utf-8'))
'd0:9f:d1:80:d0:b8:d0:b2:d0:b5:d1:82:20:d0:bc:d0:b8:d1:80:21:21'

In Python 2, passieren czu ordersten, das heißt ord(c)- weitere Beispiele:

>>> ":".join("{:02x}".format(ord(c)) for c in a_string.encode('utf-8'))
'd0:9f:d1:80:d0:b8:d0:b2:d0:b5:d1:82:20:d0:bc:d0:b8:d1:80:21:21'
>>> ":".join(format(ord(c), '02x') for c in a_string.encode('utf-8'))
'd0:9f:d1:80:d0:b8:d0:b2:d0:b5:d1:82:20:d0:bc:d0:b8:d1:80:21:21'

1
@ not2qubit Bitte versuchen Sie diese Beispiele noch einmal - ich habe mir ein wenig Zeit genommen, um die Unterschiede zwischen Python 2 und 3 zu beheben, und anscheinend habe ich diese ursprünglich nur für Python 2 geschrieben. Und danke, dass Sie meine Antwort beantwortet haben!
Aaron Hall

Ja, das hat es geschafft. Danke dir!
not2qubit

8

Sie können hexdump's verwenden

import hexdump
hexdump.dump("Hello World", sep=":")

(anhängen, .lower()wenn Sie Kleinbuchstaben benötigen). Dies funktioniert sowohl für Python 2 als auch für Python.


Auch ein Problem, auf das ich gestoßen bin. Wenn Sie Probleme bei der Installation von Hexdump oder einem anderen Paket haben, ist es aufgrund der Proxy-Einstellungen üblich, Pip mit der Proxy-Option pip install -U hexdump --proxy http://proxy.address:port
Eduard Florinescu,

Eigentlich habe ich den Fehler gemacht, sudomit zu verwenden pip, was durcheinander gebracht hat pacman...
Tobias Kienzler

6

Mit der Map- und Lambda-Funktion kann eine Liste von Hex-Werten erstellt werden, die gedruckt (oder für andere Zwecke verwendet) werden können.

>>> s = 'Hello 1 2 3 \x01\x02\x03 :)'

>>> map(lambda c: hex(ord(c)), s)
['0x48', '0x65', '0x6c', '0x6c', '0x6f', '0x20', '0x31', '0x20', '0x32', '0x20', '0x33', '0x20', '0x1', '0x2', '0x3', '0x20', '0x3a', '0x29']

[hex(ord(c)) for c in s]
Boris

2

Dies kann auf folgende Arten erfolgen:

from __future__ import print_function
str = "Hello World !!"
for char in str:
    mm = int(char.encode('hex'), 16)
    print(hex(mm), sep=':', end=' ' )

Die Ausgabe erfolgt in hexadezimaler Form wie folgt:

0x48 0x65 0x6c 0x6c 0x6f 0x20 0x57 0x6f 0x72 0x6c 0x64 0x20 0x21 0x21


Wo finde ich die Zukunft
Tofutim

Zum späteren Nachschlagen __future__steht eine Standardbibliothek in neueren Versionen von Python 2 zur Verfügung, mit der Funktionen normalerweise nur in Python 3 abwärtskompatibel gemacht werden können. In dieser Antwort wird die print(text)Funktion "Druckfunktion" abgerufen, die die print textSyntax von Python 2 ersetzt. Weitere Informationen finden Sie in den Python-Dokumenten .
Eric Reed

2

Ein bisschen allgemeiner für diejenigen, die sich nicht für Python3 oder Doppelpunkte interessieren:

from codecs import encode

data = open('/dev/urandom', 'rb').read(20)
print(encode(data, 'hex'))      # data

print(encode(b"hello", 'hex'))  # string

0

Verwendung base64.b16encodein Python2 (integriert)

>>> s = 'Hello world !!'
>>> h = base64.b16encode(s)
>>> ':'.join([h[i:i+2] for i in xrange(0, len(h), 2)]
'48:65:6C:6C:6F:20:77:6F:72:6C:64:20:21:21'

Das funktioniert nicht. Was verwenden Sie für den Import und warum nicht .decode()?
not2qubit

0

Nur zur Vereinfachung, sehr einfach.

def hexlify_byteString(byteString, delim="%"):
    ''' very simple way to hexlify a bytestring using delimiters '''
    retval = ""
    for intval in byteString:
        retval += ( '0123456789ABCDEF'[int(intval / 16)])
        retval += ( '0123456789ABCDEF'[int(intval % 16)])
        retval += delim
    return( retval[:-1])

hexlify_byteString(b'Hello World!', ":")
# Out[439]: '48:65:6C:6C:6F:20:57:6F:72:6C:64:21'

0

Für etwas, das mehr Leistung bietet als ''.format(), können Sie Folgendes verwenden:

>>> ':'.join( '%02x'%(v if type(v) is int else ord(v)) for v in 'Hello World !!' )
'48:65:6C:6C:6F:20:77:6F:72:6C:64:20:21:21'
>>> 
>>> ':'.join( '%02x'%(v if type(v) is int else ord(v)) for v in b'Hello World !!' )
'48:65:6C:6C:6F:20:77:6F:72:6C:64:20:21:21'
>>> 

Entschuldigung, das könnte nicht schöner aussehen. Es
wäre schön, wenn man es einfach tun könnte '%02x'%v, aber das dauert nur int ...
aber Sie werden mit Byte-Strings b''ohne die Logik zur Auswahl stecken bleiben ord(v).

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.