Pracując z Pythonem 2.7, zastanawiam się, jaka jest prawdziwa zaleta w używaniu typu unicode
zamiast str
, ponieważ oba wydają się być w stanie przechowywać ciągi Unicode. Czy jest jakiś szczególny powód oprócz możliwości ustawienia kodów Unicode w unicode
łańcuchach za pomocą znaku ucieczki \
?:
Wykonanie modułu z:
# -*- coding: utf-8 -*-
a = 'á'
ua = u'á'
print a, ua
Wyniki w: á, á
EDYTOWAĆ:
Więcej testów przy użyciu powłoki Pythona:
>>> a = 'á'
>>> a
'\xc3\xa1'
>>> ua = u'á'
>>> ua
u'\xe1'
>>> ua.encode('utf8')
'\xc3\xa1'
>>> ua.encode('latin1')
'\xe1'
>>> ua
u'\xe1'
Zatem unicode
ciąg wydaje się być zakodowany przy użyciu latin1
zamiast, utf-8
a nieprzetworzony ciąg jest kodowany przy użyciu utf-8
? Jestem teraz jeszcze bardziej zdezorientowany! : S
unicode
, to tylko abstrakcją Unicode;unicode
można przekonwertować nastr
z pewnym kodowaniem (nputf-8
.).Odpowiedzi:
unicode
jest przeznaczony do obsługi tekstu . Tekst to sekwencja punktów kodowych, które mogą być większe niż jeden bajt . Tekst może być zakodowany w zadaniu kodowania do reprezentowania tekstu jako surowego bajtów (nputf-8
,latin-1
...).Zauważ, że
unicode
nie jest zakodowane ! Wewnętrzna reprezentacja używana przez Pythona to szczegół implementacji i nie powinieneś się tym przejmować, o ile jest w stanie reprezentować żądane punkty kodowe.Wręcz przeciwnie,
str
w Pythonie 2 jest to zwykła sekwencja bajtów . Nie przedstawia tekstu!Można go traktować
unicode
jako ogólną reprezentację pewnego tekstu, który można zakodować na wiele różnych sposobów w sekwencję danych binarnych reprezentowanych przezstr
.Uwaga: w Pythonie 3
unicode
zmieniono nazwę nastr
i istnieje nowybytes
typ dla zwykłej sekwencji bajtów.Niektóre różnice, które możesz zobaczyć:
Zauważ, że używając
str
masz kontrolę niższego poziomu na pojedynczych bajtach określonej reprezentacji kodowania, podczas gdy używaszunicode
możesz kontrolować tylko na poziomie punktu kodu. Na przykład możesz:To, co wcześniej było poprawne w UTF-8, już nie jest. Używając łańcucha Unicode, nie możesz działać w taki sposób, że wynikowy ciąg nie jest prawidłowym tekstem Unicode. Możesz usunąć punkt kodowy, zastąpić punkt kodowy innym punktem kodowym itp., Ale nie możesz zepsuć wewnętrznej reprezentacji.
źródło
unicode
obiektówencode()
, wydaje mi się, że najpierw musimy jawnie je ustawić w odpowiednim formacie kodowania, ponieważ nie wiemy, który z nich jest używany wewnętrznie do reprezentowaniaunicode
wartości.unicode
obiektu.unicode
nie jest zakodowane, jest po prostu błędne. UTF-16 / UCS-2 i UTF-32 / UCS-4 również są kodowaniami ... iw przyszłości prawdopodobnie powstanie ich więcej. Chodzi o to, że tylko dlatego, że nie powinieneś przejmować się szczegółami implementacji (a nawet nie powinieneś!), Nadal nie oznacza, żeunicode
nie jest to kodowane. Tak, oczywiście. Czy to możliwe.decode()
, to zupełnie inna historia.unicode
wewnętrzna reprezentacja obiektu może być dowolna, w tym niestandardowa. W szczególności, w python3 +unicode
nie wykorzystywać niestandardową reprezentację wewnętrzną, która zmienia się także w zależności od danych zawartych. Jako takie nie jest to standardowe kodowanie . Unicode jako standard tekstowy definiuje tylko punkty kodowe, które są abstrakcyjną reprezentacją tekstu, istnieje mnóstwo sposobów kodowania Unicode w pamięci, w tym standardowy utf-X itp. Python używa własnego sposobu na zwiększenie wydajności.unicode
, ponieważ nie używa on UTF-16 ani UTF-32. Używa reprezentacji ad hoc, a jeśli chcesz zakodować dane na rzeczywiste bajty, musisz użyćencode
. Ponadto: język nie określa sposobuunicode
implementacji, więc różne wersje lub implementacje Pythona mogą (i mają ) różne wewnętrzne reprezentacje.Unicode i kodowanie to zupełnie inne, niepowiązane ze sobą rzeczy.
Unicode
Przypisuje numeryczny identyfikator do każdego znaku:
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:
ASCII
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 .
ISO 8859-1 (aka Latin-1)
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:
Możesz zobaczyć wszystkie mapowania w tej tabeli .
UTF-8
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:
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ć:
Ale mogę po prostu powiedzieć:
A jeśli mam UTF-8 , mogę powiedzieć:
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:
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
.Gdy spojrzysz na wartość
a
, jej zawartość 11000011 10100001 jest formatowana jako liczba szesnastkowa 0xC3 0xA1 i wyświetlana jako'\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):Kiedy patrzysz na wartość
ua
, Python mówi ci, że zawiera punkt kodowy U + 00E1: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:
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:
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.źródło
Twój terminal jest skonfigurowany do UTF-8.
Fakt, że drukarnia
a
to przypadek; piszesz surowe bajty UTF-8 na terminalu.a
to wartość o długości dwa , zawierająca dwa bajty, wartości szesnastkowe C3 i A1, natomiastua
jest wartością w formacie Unicode o długości jeden , zawierającą punkt kodowy U + 00E1.Ta różnica w długości jest głównym powodem używania wartości Unicode; nie można łatwo zmierzyć liczby znaków tekstowych w ciągu bajtów;
len()
z ciągiem bajtów powie Ci ile bajtów zostały wykorzystane, a nie jak wiele znaków zostały zakodowane.Widać różnicę podczas kodowania wartości Unicode różnych kodowań wyjściowych:
Zauważ, że pierwsze 256 punktów kodowych standardu Unicode odpowiada standardowi Latin 1, więc punkt kodowy U + 00E1 jest kodowany jako Latin 1 jako bajt z wartością szesnastkową E1.
Co więcej, Python używa kodów ucieczki w reprezentacjach zarówno ciągów znaków Unicode, jak i bajtów, a niskie punkty kodowe, które nie są drukowane w ASCII, są również reprezentowane za pomocą
\x..
wartości ucieczki. Dlatego ciąg Unicode z punktem kodowym od 128 do 255 wygląda tak, jak kodowanie Latin 1. Jeśli masz ciąg znaków Unicode z punktami kodowymi powyżej U + 00FF,\u....
zamiast tego używana jest inna sekwencja ucieczki , z czterocyfrową wartością szesnastkową.Wygląda na to, że nie rozumiesz jeszcze w pełni, jaka jest różnica między Unicode a kodowaniem. Przed kontynuowaniem przeczytaj następujące artykuły:
Absolutne minimum Każdy programista absolutnie, pozytywnie musi wiedzieć o Unicode i zestawach znaków (bez wymówek!) Joela Spolsky'ego
HOWTO Python Unicode
Pragmatyczny Unicode autorstwa Neda Batcheldera
źródło
\xe1
w alfabecie łacińskim 1.Gdy zdefiniujesz a jako Unicode, znaki a i á są równe. W przeciwnym razie á liczy się jako dwa znaki. Spróbuj len (a) i len (au). Oprócz tego może być konieczne kodowanie podczas pracy z innymi środowiskami. Na przykład, jeśli używasz md5, otrzymujesz różne wartości a i ua
źródło