Cetak string sebagai hex byte?

155

Saya memiliki string ini: Hello world !!dan saya ingin mencetaknya menggunakan Python as 48:65:6c:6c:6f:20:77:6f:72:6c:64:20:21:21.

hex() hanya berfungsi untuk bilangan bulat.

Bagaimana itu bisa dilakukan?

Eduard Florinescu
sumber
Jika idenya adalah mengembalikan hanya nilai hex 2 digit, maka pertanyaan ini menyiratkan penggunaan string byte (yaitu Python 2 stratau Python 3 bytestring), karena tidak ada transformasi tegas karakter ke dalam integer di 0 ... 255. Dengan demikian, karakter string (Python 2 unicodedan Python 3 str) pertama-tama memerlukan beberapa pengkodean sebelum dapat dikonversi dalam format heksadesimal ini. Jawaban Aaron Hall mencontohkan ini.
Eric O Lebigot

Jawaban:

227

Anda dapat mengubah string Anda menjadi generator int, menerapkan pemformatan hex untuk setiap elemen dan bersinggungan dengan pemisah:

>>> 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
Fedor Gogolev
sumber
3
Perhatikan bahwa dalam python3, konsep pencetakan strsebagai hex tidak benar-benar masuk akal; Anda ingin mencetak bytesobjek sebagai hex (konversikan strke bytesdengan menelepon .encode()).
mic_e
8
Bahkan, ini menghasilkan output yang tidak valid di python3: ":".join("{:02x}".format(ord(c)) for c in 'løl')return '6c:f8:6c', sementara ":".join("{:02x}".format(c) for c in 'løl'.encode())menghasilkan representasi utf-8 yang benar '6c:c3:b8:6c'.
mic_e
2
Pertanyaan dan jawaban ini berasumsi bahwa input Anda tidak pernah mengandung karakter non-ASCII. Jika input Anda mungkin berisi hal-hal seperti emoji atau sistem penulisan berbasis non-Latin, Anda mungkin ingin menggunakan ":".join("{:04x}".format(ord(c)) for c in s)(ganti 02xdengan 04xke-pad nol setiap angka menjadi 4 digit) sebagai gantinya
Boris
@mic_e Kenapa ini? Scapy membuat referensi untuk ini ketika Anda mencobanya di interpreter tertanam. WARNING: Calling str(pkt) on Python 3 makes no sense!
sherrellbc
157
':'.join(x.encode('hex') for x in 'Hello World!')
Estetikus
sumber
3
Bagaimana melakukan ini di 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))untuk memasukkan ':'setelah setiap dua digit hex di dalamnya.
jfs
2
Tidak berfungsi pada Python 3.LookupError: 'hex' is not a text encoding; use codecs.encode() to handle arbitrary codecs
Boris
55

Untuk Python 2.x:

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

Kode di atas tidak akan berfungsi dengan Python 3.x , untuk 3.x, kode di bawah ini akan berfungsi:

':'.join(hex(ord(x))[2:] for x in 'Hello World!')
Kelvin Hu
sumber
1
juga harus dicatat, bahwa nanti juga JUGA bekerja dengan python2.x DAN itu juga akan berfungsi untuk karakter non-ascii
raudi
1
Tetapi juga perhatikan bahwa yang terakhir tidak memasukkan nol di depan: hex (ord ("\ x00")) [2:] adalah "0" dan "\ x00" .encode ("hex") == "00"
Will Daniels
3
Mengapa Anda memutuskan untuk memposting ini sebagai jawaban baru, berbulan-bulan setelah kedua solusi ini ditawarkan oleh pengguna lain? Jika intinya adalah untuk memperjelas kompatibilitas versi, akan lebih masuk akal untuk menyarankan pengeditan untuk jawaban yang ada.
Air
2
Seperti disebutkan di tempat lain, jawaban ini bahkan tidak benar ketika seseorang bergerak melampaui ascii dan menganggap unicode. ':'. join (hex (ord (x)) [2:] untuk x dalam 'løl') salah mencetak '6c: f8: 6c' sedangkan output yang benar adalah '6c: c3: b8: 6c'.
mcduffee
23

Jawaban lain dalam dua baris yang sebagian mungkin lebih mudah dibaca, dan membantu dengan men-debug jeda baris atau karakter aneh lainnya dalam sebuah string:

Untuk Python 2.7

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

Untuk Python 3.7 (tidak diuji pada semua rilis 3)

for character in string:
    print(character, character.encode('utf-8').hex())
copeland3300
sumber
Ini tidak berfungsi pada Python 3.6.8 (setidaknya): "hex" bukan pengkodean string. codecs.encode(<bytestring>, "hex")tidak bekerja.
Eric O Lebigot
2
Ah, terima kasih banyak atas informasinya ... ya ini pasti ditulis untuk Python 2.7. Saya akan memperbarui jawaban saya untuk memasukkan cara melakukannya untuk Python 3.7.
copeland3300
Verified, 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()+"||"); (keluar)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

Beberapa pelengkap jawaban Fedor Gogolev:

Pertama, jika string berisi karakter yang 'kode ASCII' di bawah 10, mereka tidak akan ditampilkan seperti yang diperlukan. Dalam hal itu, format yang benar adalah {: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'
                                           ^^

Kedua, jika "string" Anda sebenarnya adalah "byte string" - dan karena perbedaannya penting dalam Python 3 - Anda mungkin lebih suka yang berikut ini:

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

Harap perhatikan bahwa tidak perlu konversi dalam kode di atas karena objek byte didefinisikan sebagai "urutan bilangan bulat yang tidak dapat diubah dalam kisaran 0 <= x <256" .

Sylvain Leroux
sumber
11

Cetak string sebagai hex byte?

Jawaban yang diterima memberi:

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

pengembalian:

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

Jawaban yang diterima hanya berfungsi selama Anda menggunakan byte (kebanyakan karakter ascii). Tetapi jika Anda menggunakan unicode, misal:

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

Anda perlu mengonversi ke byte entah bagaimana.

Jika terminal Anda tidak menerima karakter ini, Anda dapat mendekode dari UTF-8 atau menggunakan nama (sehingga Anda dapat menempel dan menjalankan kode bersama dengan saya):

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

Jadi kita melihat bahwa:

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

kembali

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

hasil yang buruk / tidak terduga - ini adalah poin kode yang bergabung untuk membuat grafik yang kita lihat di Unicode, dari Konsorsium Unicode - mewakili bahasa di seluruh dunia. Namun, ini bukan cara kami menyimpan informasi ini sehingga dapat ditafsirkan oleh sumber lain.

Untuk mengizinkan sumber lain menggunakan data ini, kita biasanya perlu mengonversi ke pengkodean UTF-8, misalnya, untuk menyimpan string ini dalam byte ke disk atau untuk mempublikasikan ke html. Jadi kita memerlukan pengkodean untuk mengonversi titik kode ke unit kode UTF-8 - dengan Python 3, ordtidak diperlukan karena bytesiterables bilangan bulat:

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

Atau mungkin lebih elegan, menggunakan f-string baru (hanya tersedia di 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'

Dalam Python 2, beralih cke yang ordpertama, yaitu ord(c)- lebih banyak contoh:

>>> ":".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'
Aaron Hall
sumber
1
@ not2qubit tolong coba contoh-contoh ini lagi - saya mengambil sedikit waktu untuk mengatasi perbedaan antara Python 2 dan 3, dan tampaknya saya awalnya hanya menulis ini untuk Python 2. Dan terima kasih telah QA'ing jawaban saya!
Aaron Hall
Ya, itu berhasil. Terima kasih!
not2qubit
8

Anda dapat menggunakan hexdump's

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

(tambahkan .lower()jika Anda membutuhkan huruf kecil). Ini berfungsi baik untuk Python 2 & 3.

Tobias Kienzler
sumber
Juga masalah yang saya temui, jika Anda memiliki masalah menginstal hexdump atau paket lain biasanya karena pengaturan proxy coba jalankan pip dengan opsi proxy pip install -U hexdump --proxy http://proxy.address:port
Eduard Florinescu
Sebenarnya saya membuat kesalahan sudodengan menggunakan pip, yang mengacaukan pacman...
Tobias Kienzler
6

Menggunakan fungsi peta dan lambda dapat menghasilkan daftar nilai hex, yang dapat dicetak (atau digunakan untuk tujuan lain)

>>> 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']
BrendanSimon
sumber
[hex(ord(c)) for c in s]
Boris
2

Ini dapat dilakukan dengan cara-cara berikut:

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

Output dari ini adalah dalam hex sebagai berikut:

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

Ghansham
sumber
di mana saya menemukan masa depan
tofutim
Untuk referensi di masa mendatang, __future__adalah pustaka standar yang tersedia dalam versi terbaru dari Python 2 yang dapat digunakan untuk membuat fitur-fitur yang biasanya hanya di Python 3 kompatibel dengan mundur. Dalam jawaban ini, ini digunakan untuk mendapatkan fitur print(text)"fungsi cetak", yang menggantikan print textsintaks dari Python 2. Lihat dokumen Python .
Eric Reed
2

Sedikit lebih umum bagi mereka yang tidak peduli tentang Python3 atau titik dua:

from codecs import encode

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

print(encode(b"hello", 'hex'))  # string
Gringo Suave
sumber
0

Menggunakan base64.b16encodedi python2 ( bawaannya )

>>> 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'
Shiplu Mokaddim
sumber
Ini tidak berhasil. Apa yang Anda gunakan untuk impor dan mengapa tidak digunakan .decode()?
not2qubit
0

Hanya untuk kenyamanan, sangat sederhana.

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'
BerndSchmitt
sumber
0

untuk sesuatu yang menawarkan lebih banyak kinerja daripada ''.format(), Anda dapat menggunakan ini:

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

maaf ini tidak bisa terlihat lebih bagus
akan lebih baik jika seseorang bisa melakukannya '%02x'%v, tetapi itu hanya membutuhkan int ...
tetapi Anda akan terjebak dengan byte-string b''tanpa logika untuk memilih ord(v).

Tcll
sumber