In một chuỗi dưới dạng byte hex?


155

Tôi có chuỗi này: Hello world !! và tôi muốn in nó bằng Python 48:65:6c:6c:6f:20:77:6f:72:6c:64:20:21:21.

hex() chỉ hoạt động cho số nguyên.

Nó được hoàn thiện bằng cách nào?


Nếu ý tưởng là chỉ trả về các giá trị hex 2 chữ số, thì câu hỏi này ngụ ý việc sử dụng các chuỗi byte (tức là Python 2 strhoặc Python 3 bytestring), vì không có sự biến đổi không rõ ràng của một ký tự thành một số nguyên trong 0 0 255. Do đó, các chuỗi ký tự (Python 2 unicodevà Python 3 str) trước tiên yêu cầu một số mã hóa trước khi có thể chuyển đổi theo định dạng thập lục phân này. Câu trả lời của Aaron Hall minh họa điều này.
Eric O Lebigot

Câu trả lời:


227

Bạn có thể chuyển đổi chuỗi của mình thành trình tạo int, áp dụng định dạng hex cho từng thành phần và xen kẽ với dấu phân cách:

>>> 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
Lưu ý rằng trong python3, khái niệm in strdưới dạng hex không thực sự có ý nghĩa; bạn sẽ muốn in bytesđối tượng dưới dạng hex (chuyển đổi strsang bytesbằng cách gọi .encode()).
mic_e

8
Trong thực tế, điều này tạo ra đầu ra không hợp lệ trong python3: ":".join("{:02x}".format(ord(c)) for c in 'løl')return '6c:f8:6c', trong khi ":".join("{:02x}".format(c) for c in 'løl'.encode())tạo ra đại diện utf-8 chính xác '6c:c3:b8:6c'.
mic_e

2
Câu hỏi và loại câu trả lời này giả định rằng đầu vào của bạn không bao giờ chứa các ký tự không phải ASCII. Nếu đầu vào của bạn có thể chứa những thứ như biểu tượng cảm xúc hoặc hệ thống viết không dựa trên tiếng Latinh, bạn có thể muốn sử dụng ":".join("{:04x}".format(ord(c)) for c in s)(thay thế 02xbằng 04xsố 0 mỗi số thành 4 chữ số) thay vào đó
Boris

@mic_e Tại sao lại thế này? Scacco làm tham chiếu đến điều này khi bạn thử nó trong trình thông dịch nhúng. WARNING: Calling str(pkt) on Python 3 makes no sense!
sherrellbc

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

3
Làm thế nào để làm điều này trong 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))để chèn ':'sau mỗi hai chữ số hex trong đó.
jfs

2
Không hoạt động trên Python 3.LookupError: 'hex' is not a text encoding; use codecs.encode() to handle arbitrary codecs
Boris

55

Đối với Python 2.x:

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

Mã ở trên sẽ không hoạt động với Python 3.x , đối với 3.x, mã bên dưới sẽ hoạt động:

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

1
cũng cần lưu ý rằng sau này
C ALNG

1
Nhưng cũng lưu ý rằng cái sau không đệm các số 0 đứng đầu: hex (ord ("\ x00")) [2:] là "0" và "\ x00" .encode ("hex") == "00"
Will Daniels

3
Tại sao bạn quyết định đăng bài này dưới dạng câu trả lời mới, vài tháng sau khi cả hai giải pháp này được cung cấp bởi người dùng khác? Nếu mục đích là làm rõ tính tương thích của phiên bản, thì sẽ có ý nghĩa hơn khi đề xuất các chỉnh sửa cho các câu trả lời hiện có.
Không khí

2
Như đã lưu ý ở nơi khác, câu trả lời này thậm chí không chính xác một khi người ta vượt ra ngoài ascii và xem xét unicode. ':'. tham gia (hex (ord (x)) [2:] cho x in 'løl') in không chính xác '6c: f8: 6c' trong khi đầu ra đúng là '6c: c3: b8: 6c'.
mcduffee

23

Một câu trả lời khác trong hai dòng mà một số người có thể thấy dễ đọc hơn và giúp gỡ lỗi ngắt dòng hoặc các ký tự kỳ lạ khác trong chuỗi:

Đối với Python 2.7

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

Đối với Python 3.7 (không được thử nghiệm trên tất cả các bản phát hành của 3)

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

Điều này không hoạt động kể từ Python 3.6.8 (ít nhất): "hex" không phải là mã hóa chuỗi. codecs.encode(<bytestring>, "hex")không hoạt động, mặc dù.
Eric O Lebigot

2
À, rất cảm ơn vì thông tin ... vâng, điều này chắc chắn được viết cho Python 2.7. Tôi sẽ cập nhật câu trả lời của mình để bao gồm cách thực hiện cho Python 3.7.
copeland3300

Đã xác minh, 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()+"||"); (ra)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

Một số bổ sung cho câu trả lời của Fedor Gogolev:

Đầu tiên, nếu chuỗi chứa các ký tự có 'mã ASCII' dưới 10, chúng sẽ không được hiển thị theo yêu cầu. Trong trường hợp đó, định dạng đúng phải là {: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'
                                           ^^

Thứ hai, nếu "chuỗi" của bạn trong thực tế là "chuỗi byte" - và vì sự khác biệt quan trọng trong Python 3 - bạn có thể thích những điều sau:

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

Xin lưu ý rằng không cần chuyển đổi trong đoạn mã trên vì các đối tượng byte được định nghĩa"một chuỗi số nguyên bất biến trong phạm vi 0 <= x <256" .


11

In một chuỗi dưới dạng byte hex?

Câu trả lời được chấp nhận cho:

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

trả về:

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

Câu trả lời được chấp nhận chỉ hoạt động miễn là bạn sử dụng byte (chủ yếu là ký tự ascii). Nhưng nếu bạn sử dụng unicode, vd:

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

Bạn cần phải chuyển đổi sang byte bằng cách nào đó.

Nếu thiết bị đầu cuối của bạn không chấp nhận các ký tự này, bạn có thể giải mã từ UTF-8 hoặc sử dụng tên (để bạn có thể dán và chạy mã cùng với tôi):

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

Vì vậy, chúng tôi thấy rằng:

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

trả lại

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

một kết quả kém / bất ngờ - đây là những điểm mã kết hợp để tạo ra các biểu đồ mà chúng ta thấy trong Unicode, từ Hiệp hội Unicode - đại diện cho các ngôn ngữ trên toàn thế giới. Đây không phải cách chúng tôi thực sự lưu trữ thông tin này để nó có thể được giải thích bởi các nguồn khác.

Để cho phép một nguồn khác sử dụng dữ liệu này, chúng ta thường cần phải chuyển đổi sang mã hóa UTF-8, ví dụ, để lưu chuỗi này theo byte vào đĩa hoặc xuất bản thành html. Vì vậy, chúng ta cần mã hóa đó để chuyển đổi các điểm mã thành các đơn vị mã của UTF-8 - trong Python 3, ordkhông cần thiết bởi vì bytescó thể lặp lại các số nguyên:

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

Hoặc có lẽ thanh lịch hơn, sử dụng chuỗi f mới (chỉ có sẵn trong 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'

Trong Python 2, chuyển cđến ordđầu tiên, tức là ord(c)- ví dụ khác:

>>> ":".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 vui lòng thử lại các ví dụ này - Tôi đã mất một ít thời gian để giải quyết sự khác biệt giữa Python 2 và 3, và rõ ràng ban đầu tôi chỉ viết những điều này cho Python 2. Và cảm ơn vì đã trả lời câu hỏi của tôi!
Aaron Hall

Vâng, điều đó đã làm nó. Cảm ơn bạn!
not2qubit

8

Bạn có thể sử dụng hexdump's

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

(chắp thêm .lower()nếu bạn yêu cầu chữ thường). Điều này hoạt động cho cả Python 2 & 3.


Đây cũng là một vấn đề tôi gặp phải, nếu bạn gặp vấn đề khi cài đặt hexdump hoặc bất kỳ gói nào khác thì đó là chuyện thường gặp vì cài đặt proxy hãy thử chạy pip với tùy chọn proxy pip install -U hexdump --proxy http://proxy.address:port
Eduard Florinescu

Thật sự tôi đã sai lầm khi sử dụng sudovới pip, mà sai lầm pacman...
Tobias KIENZLER

6

Sử dụng chức năng map và lambda có thể tạo ra một danh sách các giá trị hex, có thể được in (hoặc được sử dụng cho các mục đích khác)

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

Điều này có thể được thực hiện theo những cách sau:

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

Đầu ra của cái này sẽ ở dạng hex như sau:

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


Tôi tìm thấy tương lai ở đâu
tofutim 29/03/18

Để tham khảo trong tương lai, __future__là một thư viện tiêu chuẩn có sẵn trong các phiên bản gần đây của Python 2 có thể được sử dụng để làm cho các tính năng thường chỉ tương thích với Python 3 tương thích ngược. Trong câu trả lời này, nó được sử dụng để có được print(text)tính năng "chức năng in", thay thế print textcú pháp từ Python 2. Xem tài liệu Python .
Eric Reed

2

Nói chung hơn một chút cho những người không quan tâm đến Python3 hoặc dấu hai chấm:

from codecs import encode

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

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

0

Sử dụng base64.b16encodetrong python2 (tích hợp sẵn)

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

Điều này không hoạt động. Bạn đang sử dụng để nhập khẩu và tại sao không sử dụng .decode()?
not2qubit

0

Chỉ để thuận tiện, rất đơn giản.

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

đối với một cái gì đó cung cấp hiệu suất cao hơn ''.format(), bạn có thể sử dụng điều này:

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

xin lỗi, điều này không thể đẹp hơn
nếu người ta có thể làm một cách đơn giản '%02x'%v, nhưng điều đó chỉ mất int ...
nhưng bạn sẽ bị mắc kẹt với chuỗi byte b''mà không có logic để chọn ord(v).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.