2017-03-19 27 views
6

W python2:Dlaczego wynik drukowania w python2 i python3 jest inny z tym samym ciągiem?

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

W python3:

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

Dlaczego to ma bajt "\xc2" tutaj?

Edit:

myślę kiedy ciąg miały charakter non-ASCII, python3 dołączy bajt "\xc2" do łańcucha. (jak powiedział @Ashraful Islam)

Jak mogę tego uniknąć w python3?

+0

Jakieś inne przykłady? Czy możesz znaleźć wzór? –

Odpowiedz

9

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.

1

Domyślny typ ciągu Python 2 to ciągi bajtów. Łańcuchy bajtowe są zapisywane jako "abc", podczas gdy łańcuchy Unicode są zapisywane jako u"abc".

Domyślny typ ciągu Python 3 to ciągi Unicode. Łańcuchy bajtowe są zapisywane jako b"abc", podczas gdy ciągi znaków Unicode są zapisywane jako "abc" (u"abc"). ponieważ istnieją miliony znaków Unicode, drukowanie ich jako bajtów wymaga kodowania (UTF-8 w twoim przypadku), które wymaga wielu bajtów na punkt kodowy.

Najpierw użyj łańcucha bajtów w Pythonie 3, aby uzyskać ten sam typ Pythona 2. Następnie, ponieważ kod print Pythona 3 oczekuje ciągów Unicode, użyj sys.stdout.buffer.write, aby pisać do surowego interfejsu stdout, który oczekuje ciągów bajtów.

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

Pamiętaj, że jeśli piszesz do pliku, występują podobne problemy. W przypadku braku tłumaczenia kodowania otwórz pliki w trybie binarnym 'wb' i wpisz ciągi bajtów.

Powiązane problemy