Rozważmy następujący fragment kodu:
import sys
for i in range(128, 256):
sys.stdout.write(chr(i))
Uruchom ten Pythona 2 i spojrzeć na wynik z hexdump -C
:
00000000 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f |................|
et cetera. Bez niespodzianek; 128 bajtów z 0x80
do 0xff
.
Zrób to samo z Pythona 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 |................|
Podsumowując:
- Wszystko od
0x80
do 0xbf
został 0xc2
poprzedzany.
- Wszystko od
0xc0
do 0xff
ma bit 6 ustawiony na zero i ma 0xc3
z góry.
Co się tutaj dzieje?
W języku Python 2 ciągi znaków są w formacie ASCII i konwersja nie jest wykonywana. Powiedz to do napisz coś poza zakresem 0-127 ASCII, mówi "okey-doke!" I po prostu zapisuje te bajty. Prosty.
W języku Python 3 ciągi znaków to Unicode. Gdy znaki spoza ASCII są napisane, muszą być w pewnym sensie kodowane zakodowane w następujący sposób:. Domyślne kodowanie to UTF-8.
Jak te wartości są kodowane w UTF-8?
punkty kod z 0x80
do 0x7ff
są zakodowane w sposób następujący
110vvvvv 10vvvvvv
Jeżeli 11 v
postacie są bity punktu kodowego.
Zatem:
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
Więc dlatego dostajesz c2
przed 87
.
Jak uniknąć tego wszystkiego w Pythonie 3? Użyj typu bytes
.
Jakieś inne przykłady? Czy możesz znaleźć wzór? –