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?


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

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

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

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

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


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'

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.


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

[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


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

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'

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'

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

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.