Unicode i kodowanie to zupełnie inne, niepowiązane ze sobą rzeczy.
Unicode
Przypisuje numeryczny identyfikator do każdego znaku:
- 0x41 → A
- 0xE1 → á
- 0x414 → Д
Tak więc Unicode przypisuje liczbę 0x41 do A, 0xE1 do á i 0x414 do Д.
Nawet mała strzałka →, której użyłem, ma swój numer Unicode, to 0x2192. Nawet emoji mają swoje numery Unicode, 😂 to 0x1F602.
Możesz sprawdzić numery Unicode wszystkich znaków w tej tabeli . W szczególności możesz znaleźć pierwsze trzy znaki powyżej tutaj , strzałkę tutaj i emoji tutaj .
Te liczby przypisane do wszystkich znaków przez Unicode nazywane są punktami kodowymi .
Wszystko to ma na celu zapewnienie możliwości jednoznacznego odniesienia się do każdej postaci. Na przykład, jeśli mówię o 😂, zamiast mówić „wiesz, ten śmiejący się emoji ze łzami” , mogę po prostu powiedzieć, punkt kodu Unicode 0x1F602 . Łatwiej, prawda?
Zwróć uwagę, że punkty kodowe Unicode są zwykle formatowane z początkiem U+
, a następnie szesnastkową wartością liczbową dopełnianą do co najmniej 4 cyfr. Tak więc powyższe przykłady to U + 0041, U + 00E1, U + 0414, U + 2192, U + 1F602.
Zakres punktów kodowych Unicode wynosi od U + 0000 do U + 10FFFF. To jest 1 114 112 liczb. 2048 z tych liczb jest używanych jako surogaty , więc pozostaje 1 112 064. Oznacza to, że Unicode może przypisać unikalny identyfikator (punkt kodowy) do 1112 064 różnych znaków. Nie wszystkie z tych punktów kodowych są jeszcze przypisane do znaku, a Unicode jest stale rozszerzany (na przykład po wprowadzeniu nowych emoji).
Ważną rzeczą do zapamiętania jest to, że wszystko, co robi Unicode, to przypisanie numerycznego identyfikatora, zwanego punktem kodowym, do każdego znaku w celu łatwego i jednoznacznego odniesienia.
Kodowania
Mapuj znaki do wzorów bitowych.
Te wzorce bitowe są używane do reprezentowania znaków w pamięci komputera lub na dysku.
Istnieje wiele różnych kodowań, które obejmują różne podzbiory znaków. W świecie anglojęzycznym najczęściej używane są następujące kodowania:
Mapy 128 znaków (punkty kodowe U + 0000 do U + 007F) do wzorów bitowych o długości 7.
Przykład:
Możesz zobaczyć wszystkie mapowania w tej tabeli .
Mapy 191 znaków (punkty kod U + 0020 U + 007E i U U + 00A0 + 00FF) do wzorów bitowych o długości 8.
Przykład:
- a → 01100001 (0x61)
- á → 11100001 (0xE1)
Możesz zobaczyć wszystkie mapowania w tej tabeli .
Mapy 1,112,064 znaków (wszystkie istniejące punkty kod Unicode) do wzorów bitowych z każdej długości 8, 16, 24 lub 32 bitów (to jest 1, 2, 3 lub 4 bajtów).
Przykład:
- a → 01100001 (0x61)
- á → 11000011 10100001 (0xC3 0xA1)
- ≠ → 11100010 10001001 10100000 (0xE2 0x89 0xA0)
- 😂 → 11110000 10011111 10011000 10000010 (0xF0 0x9F 0x98 0x82)
Drogą UTF-8 koduje znaki na ciągach bitów jest bardzo dobrze opisane tutaj .
Unicode i kodowanie
Patrząc na powyższe przykłady, staje się jasne, jak przydatny jest Unicode.
Na przykład, jeśli jestem Latin-1 i chcę wyjaśnić moje kodowanie á, nie muszę mówić:
„Koduję to a za pomocą aigu (lub jak to nazywasz) jako 11100001”
Ale mogę po prostu powiedzieć:
„Koduję U + 00E1 jako 11100001”
A jeśli mam UTF-8 , mogę powiedzieć:
„Ja z kolei koduję U + 00E1 jako 11000011 10100001”
I dla każdego jest jednoznacznie jasne, o jaką postać mamy na myśli.
Teraz przejdźmy do często pojawiającego się zamieszania
To prawda, że czasami wzorzec bitowy kodowania, jeśli interpretujesz go jako liczbę binarną, jest taki sam, jak punkt kodowy Unicode tego znaku.
Na przykład:
- Koduje ASCII a jak 1100001, który można interpretować jako liczbę szesnastkową 0x61 , a punkt kodowy Unicode jest U + 0061 .
- Latin-1 koduje á jako 11100001, co można zinterpretować jako liczbę szesnastkową 0xE1 , a punkt kodu Unicode á to U + 00E1 .
Oczywiście zostało to specjalnie zaaranżowane dla wygody. Ale powinieneś spojrzeć na to jak na czysty zbieg okoliczności . Wzorzec bitowy używany do reprezentowania znaku w pamięci nie jest w żaden sposób powiązany z punktem kodowym Unicode tego znaku.
Nikt nawet nie mówi, że jako liczbę binarną trzeba interpretować ciąg bitowy, taki jak 11100001. Wystarczy spojrzeć na to jako na sekwencję bitów, której Latin-1 używa do kodowania znaku á .
Wracając do twojego pytania
Kodowanie używane przez twój interpreter Pythona to UTF-8 .
Oto, co dzieje się w twoich przykładach:
Przykład 1
Poniższy kod koduje znak á w UTF-8. W rezultacie otrzymujemy ciąg bitów 11000011 10100001, który jest zapisywany w zmiennej a
.
>>> a = 'á'
Gdy spojrzysz na wartość a
, jej zawartość 11000011 10100001 jest formatowana jako liczba szesnastkowa 0xC3 0xA1 i wyświetlana jako '\xc3\xa1'
:
>>> a
'\xc3\xa1'
Przykład 2
Poniższe zapisuje punkt kodu Unicode á, czyli U + 00E1, w zmiennej ua
(nie wiemy, jakiego formatu danych Python używa wewnętrznie do reprezentowania punktu kodowego U + 00E1 w pamięci i nie jest to dla nas ważne):
>>> ua = u'á'
Kiedy patrzysz na wartość ua
, Python mówi ci, że zawiera punkt kodowy U + 00E1:
>>> ua
u'\xe1'
Przykład 3
Poniższy kod koduje punkt kodowy Unicode U + 00E1 (reprezentujący znak á) za pomocą UTF-8, co skutkuje wzorem bitowym 11000011 10100001. Ponownie, dla wyjścia ten wzór bitowy jest reprezentowany jako liczba szesnastkowa 0xC3 0xA1:
>>> ua.encode('utf-8')
'\xc3\xa1'
Przykład 4
Poniższy kod koduje punkt kodowy Unicode U + 00E1 (reprezentujący znak á) za pomocą Latin-1, co daje w wyniku wzór bitowy 11100001. Na wyjściu ten wzorzec bitowy jest reprezentowany jako liczba szesnastkowa 0xE1, która przypadkowo jest taka sama jak początkowa punkt kodowy U + 00E1:
>>> ua.encode('latin1')
'\xe1'
Nie ma związku między obiektem Unicode ua
a kodowaniem Latin-1. To, że punkt kodowy á to U + 00E1, a kodowanie Latin-1 á to 0xE1 (jeśli interpretujesz wzór bitowy kodowania jako liczbę binarną), jest czystym zbiegiem okoliczności.
unicode
, to tylko abstrakcją Unicode;unicode
można przekonwertować nastr
z pewnym kodowaniem (nputf-8
.).