Stampa una stringa come byte esadecimali?


155

Ho questa stringa: Hello world !!e voglio stamparla usando Python come 48:65:6c:6c:6f:20:77:6f:72:6c:64:20:21:21.

hex() funziona solo per numeri interi.

Come si può fare?


Se l'idea è di restituire solo valori esadecimali a 2 cifre, questa domanda implica l'uso di stringhe di byte (ad esempio Python 2 stro Python 3 bytestring), poiché non esiste una trasformazione inequivocabile di un carattere in un numero intero in 0 ... 255. Pertanto, le stringhe di caratteri (Python 2 unicodee Python 3 str) richiedono prima un po 'di codifica prima di essere convertibili in questo formato esadecimale. La risposta di Aaron Hall ne è un esempio.
Eric O Lebigot,

Risposte:


227

Puoi trasformare la tua stringa in un generatore int, applicare la formattazione esadecimale per ciascun elemento e intercalare con il separatore:

>>> 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
Si noti che in python3, il concetto di stampare un stras hex non ha davvero senso; ti consigliamo di stampare l' bytesoggetto come esadecimale (converti strin byteschiamando .encode()).
mic_e

8
In realtà, questo produce output valida nel python3: ":".join("{:02x}".format(ord(c)) for c in 'løl')rendimenti '6c:f8:6c', mentre ":".join("{:02x}".format(c) for c in 'løl'.encode())produce la corretta rappresentazione utf-8 '6c:c3:b8:6c'.
mic_e

2
Questa domanda e risposta presuppongono che il tuo input non contenga mai caratteri non ASCII. Se il tuo input potrebbe contenere elementi come emoji o sistemi di scrittura non latini, potresti voler utilizzare ":".join("{:04x}".format(ord(c)) for c in s)(sostituendo 02xcon 04xzero-pad ogni numero per essere composto da 4 cifre)
Boris

@mic_e Perché questo? Scapy fa un riferimento a questo quando lo provi nell'interprete incorporato. WARNING: Calling str(pkt) on Python 3 makes no sense!
Sherrellbc,

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

3
Come fare questo in Python3?
h__

6
@hyh: h = binascii.hexlify(b"Hello world !!") to get hex string. b":".join(h[i:i+2] for i in range(0, len(h), 2))da inserire ':'dopo ogni due cifre esadecimali.
jfs

2
Non funziona su Python 3.LookupError: 'hex' is not a text encoding; use codecs.encode() to handle arbitrary codecs
Boris,

55

Per Python 2.x:

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

Il codice sopra non funzionerà con Python 3.x , per 3.x, il codice qui sotto funzionerà:

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

1
va anche notato che la versione successiva funzionerà ANCHE con python2.x E funzionerà anche con caratteri non ascii
raudi,

1
Ma nota anche che quest'ultimo non riempie gli zeri iniziali: hex (ord ("\ x00")) [2:] è "0" e "\ x00" .encode ("hex") == "00"
Will Daniels

3
Perché hai deciso di pubblicare questa come una nuova risposta, mesi dopo che entrambe le soluzioni erano state offerte da altri utenti? Se il punto fosse chiarire la compatibilità della versione, sarebbe stato più sensato suggerire modifiche alle risposte esistenti.
Air

2
Come notato altrove, questa risposta non è nemmeno corretta una volta che ci si sposta oltre ascii e si considera l'unicode. ':'. join (hex (ord (x)) [2:] per x in 'løl') stampa erroneamente '6c: f8: 6c' mentre l'uscita corretta è '6c: c3: b8: 6c'.
mcduffee,

23

Un'altra risposta in due righe che alcuni potrebbero trovare più facili da leggere e aiuta con il debug delle interruzioni di riga o di altri caratteri dispari in una stringa:

Per Python 2.7

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

Per Python 3.7 (non testato su tutte le versioni di 3)

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

Questo non funziona a partire da Python 3.6.8 (almeno): "hex" non è una codifica di stringhe. codecs.encode(<bytestring>, "hex")funziona, però.
Eric O Lebigot,

2
Ah, bello grazie per le informazioni ... sì, questo è stato sicuramente scritto per Python 2.7. Aggiornerò la mia risposta per includere come farlo per Python 3.7.
copeland3300

Verificata, 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()+"||"); (fuori)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

Alcuni complementi di Fedor Gogolev rispondono:

Innanzitutto, se la stringa contiene caratteri il cui "codice ASCII" è inferiore a 10, non verranno visualizzati come richiesto. In tal caso, il formato corretto dovrebbe essere {: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'
                                           ^^

In secondo luogo, se la tua "stringa" è in realtà una "stringa di byte" - e poiché la differenza è importante in Python 3 - potresti preferire quanto segue:

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

Si noti che non è necessario eseguire la conversione nel codice sopra poiché oggetti byte sono definiti come "una sequenza immutabile di numeri interi nell'intervallo 0 <= x <256" .


11

Stampa una stringa come byte esadecimali?

La risposta accettata dà:

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

ritorna:

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

La risposta accettata funziona solo finché si utilizzano byte (principalmente caratteri ASCII). Ma se usi unicode, ad esempio:

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

È necessario convertire in byte in qualche modo.

Se il tuo terminale non accetta questi caratteri, puoi decodificare da UTF-8 o usare i nomi (così puoi incollare ed eseguire il codice insieme a me):

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}"
)

Quindi vediamo che:

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

ritorna

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

un risultato scarso / imprevisto: questi sono i punti di codice che si combinano per creare i grafemi che vediamo in Unicode, dal consorzio Unicode, che rappresentano le lingue di tutto il mondo. Questo non lo è il modo in cui effettivamente memorizzare queste informazioni in modo che possa essere interpretato da altre fonti, però.

Per consentire a un'altra fonte di utilizzare questi dati, di solito dovremmo convertire in codifica UTF-8, ad esempio, per salvare questa stringa in byte su disco o per pubblicare in html. Quindi abbiamo bisogno che la codifica per convertire i punti di codice nelle unità di codice di UTF-8 - in Python 3, ordnon sia necessaria perché bytessono iterabili di numeri interi:

>>> ":".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'

O forse più elegantemente, usando le nuove stringhe f (disponibili solo in Python 3):

>>> ":".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, passa cal ordprimo, ovvero ord(c)- altri esempi:

>>> ":".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 per favore riprova questi esempi - Mi sono preso un po 'di tempo per affrontare le differenze tra Python 2 e 3, e apparentemente in origine li ho scritti solo per Python 2. E grazie per aver risposto alla mia domanda!
Aaron Hall

Sì, lo ha fatto. Grazie!
not2qubit

8

Puoi usare hexdump's

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

(aggiungi .lower()se hai bisogno di lettere minuscole). Funziona con Python 2 e 3.


Anche un problema in cui mi sono imbattuto, se hai problemi con l'installazione di hexdump o di qualsiasi altro pacchetto, di solito a causa delle impostazioni del proxy prova a eseguire pip con l'opzione proxy pip install -U hexdump --proxy http://proxy.address:port
Eduard Florinescu,

In realtà ho fatto l'errore di usare sudocon pip, che ha incasinato pacman...
Tobias Kienzler

6

L'uso della funzione map e lambda può produrre un elenco di valori esadecimali, che possono essere stampati (o utilizzati per altri scopi)

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

Questo può essere fatto nei seguenti modi:

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

L'output di questo sarà in esadecimale come segue:

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


dove trovo il futuro
tofutim

Per riferimento futuro, __future__è disponibile una libreria standard nelle ultime versioni di Python 2 che può essere utilizzata per rendere le funzionalità normalmente compatibili solo con Python 3. In questa risposta, viene utilizzato per ottenere la print(text)funzione "funzione di stampa", che sostituisce la print textsintassi di Python 2. Vedi i documenti di Python .
Eric Reed,

2

Un po 'più generale per coloro a cui non interessa Python3 o due punti:

from codecs import encode

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

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

0

Usando base64.b16encodein python2 (il suo built-in)

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

Questo non funziona Cosa stai usando per l'importazione e perché non utilizzarlo .decode()?
not2qubit

0

Solo per comodità, molto semplice.

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

per qualcosa che offre più prestazioni di ''.format(), puoi usare questo:

>>> ':'.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'
>>> 

mi dispiace che questo non possa apparire più bello
sarebbe bello se si potesse semplicemente fare '%02x'%v, ma ci vuole solo int ...
ma rimarrai bloccato con stringhe di byte b''senza la logica da selezionare ord(v).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.