2017-03-19 21 views
6

Trong python2:Tại sao đầu ra của in ở python2 và python3 khác với cùng một chuỗi?

$ python2 -c 'print "\x08\x04\x87\x18"' | hexdump -C 
00000000 08 04 87 18 0a         |.....| 
00000005 

Trong python3:

$ python3 -c 'print("\x08\x04\x87\x18")' | hexdump -C 
00000000 08 04 c2 87 18 0a         |......| 
00000006 

Tại sao nó có byte "\xc2" đây?

Sửa:

Tôi nghĩ rằng khi chuỗi có một nhân vật phi ascii, python3 sẽ nối các byte "\xc2" vào chuỗi. (như @Ashraful Islam đã nói)

Vậy làm cách nào để tránh điều này trong python3?

+0

Bất kỳ ví dụ nào khác? Bạn có thể tìm thấy một mô hình? –

Trả lời

9

Hãy xem xét các đoạn mã sau đây:

import sys 
for i in range(128, 256): 
    sys.stdout.write(chr(i)) 

Run này với Python 2 và nhìn vào kết quả với hexdump -C:

00000000 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f |................| 

Et vân. Không có bất ngờ; 128 byte từ 0x80 đến 0xff.

Làm tương tự với Python 3:

00000000 c2 80 c2 81 c2 82 c2 83 c2 84 c2 85 c2 86 c2 87 |................| 
... 
00000070 c2 b8 c2 b9 c2 ba c2 bb c2 bc c2 bd c2 be c2 bf |................| 
00000080 c3 80 c3 81 c3 82 c3 83 c3 84 c3 85 c3 86 c3 87 |................| 
... 
000000f0 c3 b8 c3 b9 c3 ba c3 bb c3 bc c3 bd c3 be c3 bf |................| 

Để tóm tắt:

  • Tất cả mọi thứ từ 0x80 để 0xbf đã 0xc2 prepended.
  • Mọi thứ từ 0xc0 đến 0xff có bit 6 được đặt thành 0 và có 0xc3 được thêm vào trước.

Vì vậy, những gì đang diễn ra ở đây?

Trong Python 2, chuỗi là ASCII và không có chuyển đổi nào được thực hiện. Hãy cho nó để viết một cái gì đó bên ngoài phạm vi ASCII 0-127, nó nói "okey-doke!" Và chỉ cần viết những byte đó. Đơn giản.

Trong Python 3, các chuỗi là Unicode. Khi các ký tự không phải ASCII được ghi là , chúng phải được mã hóa theo một cách nào đó. Mã hóa mặc định là UTF-8.

Vì vậy, các giá trị này được mã hóa bằng UTF-8 như thế nào?

điểm Mã từ 0x80 để 0x7ff được mã hóa như sau:

110vvvvv 10vvvvvv 

Trường hợp 11 v ký tự là các bit của điểm mã.

Như vậy:

0x80     hex 
1000 0000   8-bit binary 
000 1000 0000  11-bit binary 
00010 000000   divide into vvvvv vvvvvv 
11000010 10000000 resulting UTF-8 octets in binary 
0xc2 0x80   resulting UTF-8 octets in hex 

0xc0     hex 
1100 0000   8-bit binary 
000 1100 0000  11-bit binary 
00011 000000   divide into vvvvv vvvvvv 
11000011 10000000 resulting UTF-8 octets in binary 
0xc3 0x80   resulting UTF-8 octets in hex 

Vì vậy, đó là lý do tại sao bạn đang nhận được một c2 trước 87.

Làm thế nào để tránh tất cả điều này trong Python 3? Sử dụng loại bytes.

1

Loại chuỗi mặc định của Python 2 là chuỗi byte. Các chuỗi byte được viết "abc" trong khi chuỗi Unicode được viết u"abc".

Loại chuỗi mặc định của Python 3 là chuỗi Unicode. Các chuỗi byte được viết là b"abc" trong khi các chuỗi Unicode được viết "abc" (u"abc" vẫn hoạt động). vì có hàng triệu ký tự Unicode, in chúng dưới dạng byte yêu cầu mã hóa (UTF-8 trong trường hợp của bạn) yêu cầu nhiều byte cho mỗi điểm mã.

Đầu tiên sử dụng một chuỗi byte trong Python 3 để có cùng loại Python 2. Sau đó, bởi vì print của Python 3 mong đợi các chuỗi Unicode, hãy sử dụng sys.stdout.buffer.write để ghi vào giao diện stdout thô, dự kiến ​​chuỗi byte.

python3 -c 'import sys; sys.stdout.buffer.write(b"\x08\x04\x87\x18")' 

Lưu ý rằng nếu ghi vào tệp thì có vấn đề tương tự. Để không dịch mã hóa, hãy mở các tệp ở chế độ nhị phân 'wb' và viết chuỗi byte.

Các vấn đề liên quan