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
.
Bất kỳ ví dụ nào khác? Bạn có thể tìm thấy một mô hình? –