Python str vs typy unicode

Pracując z Pythonem 2.7, zastanawiam się, jaka jest prawdziwa korzyść w używaniu typu unicode zamiast str, ponieważ oba wydają się być w stanie utrzymać ciągi Unicode. Czy istnieje jakiś szczególny powód oprócz możliwości ustawiania kodów Unicode w łańcuchach unicode za pomocą znaku escape \?:

Wykonanie modułu z:

# -*- coding: utf-8 -*-

a = 'á'
ua = u'á'
print a, ua

Wyniki w: á, á

EDIT:

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'

Więc unicode łańcuch wydaje się być zakodowany używając latin1 zamiast utf-8, a surowy łańcuch jest zakodowany za pomocą utf-8? Teraz jestem jeszcze bardziej zdezorientowany! : S

Author: Brian McCutchon, 2013-08-03

4 answers

unicode jest przeznaczony do obsługi tekstu . Tekst jest sekwencją punktów kodu, które mogą być większe niż pojedynczy bajt. Tekst może być zakodowany w określonym kodowaniu, aby reprezentować tekst jako surowe bajty (np. utf-8, latin-1...).

Zauważ, że unicode nie jest zakodowany ! Wewnętrzna reprezentacja używana przez Pythona jest szczegółem implementacji i nie powinno cię to obchodzić, o ile jest w stanie reprezentować punkty kodu, które chcę.

Przeciwnie str w Pythonie 2 jest prostą sekwencją bajtów. Nie reprezentuje tekstu!

Można myśleć o unicode jako ogólnej reprezentacji jakiegoś tekstu, który może być zakodowany na wiele różnych sposobów w sekwencję danych binarnych reprezentowanych przez str.

Uwaga: w Pythonie 3, unicode został przemianowany na str i istnieje nowy typ bytes dla prostej sekwencji bajtów.

Niektóre różnice, które można zobacz:

>>> len(u'à')  # a single code point
1
>>> len('à')   # by default utf-8 -> takes two bytes
2
>>> len(u'à'.encode('utf-8'))
2
>>> len(u'à'.encode('latin1'))  # in latin1 it takes one byte
1
>>> print u'à'.encode('utf-8')  # terminal encoding is utf-8
à
>>> print u'à'.encode('latin1') # it cannot understand the latin1 byte
�

Zauważ, że używając str masz kontrolę niższego poziomu na pojedynczych bajtach określonej reprezentacji kodowania, podczas gdy używając unicode możesz kontrolować tylko na poziomie punktu kodu. Na przykład można zrobić:

>>> 'àèìòù'
'\xc3\xa0\xc3\xa8\xc3\xac\xc3\xb2\xc3\xb9'
>>> print 'àèìòù'.replace('\xa8', '')
à�ìòù

To, co wcześniej było poprawne UTF-8, już nie jest. Używając ciągu unicode nie można operować w taki sposób, że wynikowy ciąg nie jest prawidłowym tekstem unicode. Możesz usunąć punkt kodu, zastąpić punkt kodu innym punktem kodu itp. ale nie możesz bałagan z wewnętrzną reprezentacją.

 149
Author: Bakuriu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-07 14:32:59

Twój terminal jest skonfigurowany do UTF-8.

Fakt, że drukowanie a działa jest zbiegiem okoliczności; piszesz surowe UTF-8 bajtów do terminala. a jest wartością długości two , zawierającą dwa bajty, wartości szesnastkowe C3 I A1, podczas gdy {[3] } jest wartością unicode długości one, zawierającą punkt kodowy U+00E1.

Ta różnica w długości jest jednym z głównych powodów, aby używać wartości Unicode; nie można łatwo zmierzyć liczby tekst znaków w łańcuch bajtów; len() ciągu bajtów informuje, ile bajtów zostało użytych, a nie ile znaków zakodowanych.

Możesz zobaczyć różnicę, gdy kodujesz wartość unicode do różnych kodowań wyjściowych:

>>> a = 'á'
>>> ua = u'á'
>>> ua.encode('utf8')
'\xc3\xa1'
>>> ua.encode('latin1')
'\xe1'
>>> a
'\xc3\xa1'

Zauważ, że pierwsze 256 punktów kodowych standardu Unicode odpowiada standardowi Latin 1, więc punkt kodowy U+00E1 jest kodowany do Latin 1 jako bajt o wartości szesnastkowej E1.

Ponadto Python używa kodów escape w reprezentacjach unicode i byte podobnie ciągi znaków, jak i małe punkty kodu, które nie są drukowalnymi ASCII, są reprezentowane również za pomocą wartości escape \x... Z tego powodu ciąg znaków Unicode z punktem kodowym między 128 a 255 wygląda po prostu jak kodowanie Latin 1. Jeśli masz ciąg znaków unicode z punktami kodowymi poza U + 00FF inną sekwencją escape, \u.... jest używany zamiast tego, z czterocyfrową wartością szesnastkową.

Wygląda na to, że nie do końca rozumiesz, jaka jest różnica między Unicode a kodowaniem. Proszę przeczytać następujące artykuły przed kontynuacją:

 29
Author: Martijn Pieters,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-03 15:36:00

Unicode i kodowanie to zupełnie inne, niepowiązane ze sobą rzeczy.

Unicode

Przypisuje numer ID każdemu znakowi:

  • 0x41 → A
  • 0xE1 → á
  • 0x414 → Д

Zatem Unicode przypisuje liczbę 0x41 do A, 0xE1 do á, a 0x414 do Д.

Nawet mała strzałka →, której użyłem, ma swój numer Unicode, to 0x2192. A nawet emotikony mają swoje numery Unicode, to 0x1F602.

Możesz sprawdzić numery Unicode wszystkie znaki w tej tabeli . W szczególności, można znaleźć trzy pierwsze znaki powyżej tutaj, strzałka tutaj , a emoji tutaj .

Te liczby przypisane do wszystkich znaków przez Unicode są nazywane punktami kodu .

Celem tego wszystkiego jest zapewnienie środków do jednoznacznego odniesienia się do każdego znaku. Na przykład, jeśli mówię o, zamiast powiedzieć " wiesz, ten śmiejący się emoji z łzy " , mogę tylko powiedzieć, kod Unicode 0x1f602 . Łatwiej, prawda?

należy zauważyć, że punkty kodu Unicode są zwykle formatowane za pomocą interlinii U+, a następnie szesnastkowa wartość liczbowa jest wypełniona co najmniej 4 cyframi. Tak więc powyższe przykłady to U + 0041, u+00E1, u+0414, u+2192, u+1F602.

Punkty kodu Unicode wahają się od U+0000 do U+10FFFF. To jest 1,114,112 liczb. 2048 z tych liczb są używane dla surogatów , więc pozostają 1,112,064. Oznacza to, że Unicode może przypisać unikalny identyfikator (punkt kodowy) do 1 112 064 różnych znaków. Nie wszystkie z tych punktów kodu są jeszcze przypisane do znaku, a Unicode jest stale rozszerzany(na przykład, gdy nowe emoji są wprowadzane).

Ważną rzeczą do zapamiętania jest to, że wszystko, co robi Unicode, to przypisywanie numerycznego identyfikatora, zwanego punktem kodu, do każdego znaku w celu łatwego i jednoznacznego odniesienia.

Kodowanie

Mapowanie znaków na bit wzory.

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ęstsze kodowania są następujące:

ASCII

Mapuje 128 znaków (Punkty kodowe U + 0000 do U + 007F) do wzorców bitowych o długości 7.

Przykład:

  • a → 1100001 (0x61)

Ty można zobaczyć wszystkie mapowania w tej tabeli .

ISO 8859-1 (aka Latin-1)

Mapy 191 znaków (kod wskazuje U+0020 do U+007E i U+00A0 do u+00FF) do wzorców bitowych o długości 8.

Przykład:

  • a → 01100001 (0x61)
  • á → 11100001 (0xe1)

Możesz zobaczyć wszystkie mapowania w tej tabeli .

UTF-8

Mapy 1 112 064 znaków (wszystkie istniejące Kod Unicode wskazuje) na wzorce bitowe o długości 8, 16, 24 lub 32 bity (czyli 1, 2, 3 lub 4 bajty).

Przykład:

  • a → 01100001 (0x61)
  • á → 11000011 10100001 (0xc3 0xa1)
  • ≠ → 11100010 10001001 10100000 (0xE2 0x89 0XA0)
  • → 11110000 10011111 10011000 10000010 (0xF0 0x9F 0x98 0x82)

Sposób kodowania znaków przez UTF-8 na ciągi bitowe jest bardzo dobrze opisany tutaj.

Unicode i Kodowanie

Patrząc na powyższe przykłady, staje się jasne, w jaki sposób Unicode jest użyteczny.

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 jakkolwiek to nazywacie wznoszącym się paskiem) jako 11100001" [14]}

Ale mogę tylko powiedzieć:

"koduję U + 00E1 jako 11100001"

A jeśli jestem UTF-8 , mogę powiedzieć:

"ja, w zakodowałem U + 00E1 jako 11000011 10100001 "

I jest jednoznacznie jasne dla wszystkich, którą postać mamy na myśli.

Teraz do często powstającego zamieszania

Prawdą jest, że czasami wzór bitowy kodowania, jeśli interpretujemy go jako liczbę binarną, jest taki sam jak punkt kodu Unicode tego znaku.

Na przykład:

  • ASCII koduje a jako 1100001, które można interpretować jako liczbę szesnastkową 0x61 , a punkt kodu Unicodea toU+0061 .
  • Latin-1 koduje á jako 11100001, które można interpretować jako liczbę szesnastkową 0xE1 , a punkt kodu Unicode á to U+00E1 .

Oczywiście, to zostało zorganizowane tak celowo dla wygody. Ale powinieneś spojrzeć na to jako na czysty zbieg okoliczności. Wzorzec bitowy używany do reprezentowania znaku w pamięci nie jest związany z Dowolna droga do punktu kodu Unicode tego znaku.

Nikt nawet nie mówi, że trzeba interpretować bitowy ciąg jak 11100001 jako liczbę binarną. Wystarczy spojrzeć na to jako na sekwencję bitów, których Latin-1 używa do kodowania znaku á .

Wróć do pytania

Kodowanie używane przez interpreter Pythona to UTF-8 .

Oto, co dzieje się w Twoich przykładach:

Przykład 1

Poniższy koduje znak á w UTF-8. W wyniku tego otrzymamy łańcuch bitowy 11000011 10100001, który zostanie zapisany w zmiennej a.

>>> a = 'á'

Gdy spojrzysz na wartość a, jej zawartość 11000011 10100001 jest sformatowana jako liczba szesnastkowa 0xC3 0xa1 i wyprowadzona jako '\xc3\xa1':

>>> a
'\xc3\xa1'

Przykład 2

Poniższy zapisuje punkt kodu Unicode á, który jest U+00E1, w zmiennej ua (nie wiemy, jakiego formatu danych używa Python wewnętrznie do reprezentowania punktu kodu u + 00E1 w pamięci, a to nieistotne dla nas):

>>> ua = u'á'

Kiedy spojrzysz na wartość ua, Python mówi ci, że zawiera punkt kodowy U + 00E1:

>>> ua
u'\xe1'

Przykład 3

Poniższy kod koduje kod Unicode U + 00E1 (reprezentujący znak á) za pomocą UTF-8, co daje wzór bitowy 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 kodujący Unicode punkt U+00E1 (reprezentujący znak á) z Latin-1, co daje wzór bitowy 11100001. Dla wyjścia, ten wzór bitowy jest reprezentowany jako liczba szesnastkowa 0xE1, która przez przypadek jest taka sama jak początkowy punkt kodu U+00E1:

>>> ua.encode('latin1')
'\xe1'

Nie ma związku między obiektem Unicode ua a kodowaniem Latin - 1. To, że punkt kodowy á wynosi U + 00E1, a kodowanie á łacińskie-1 wynosi 0xE1 (jeśli interpretujemy wzór bitowy kodowania jako liczbę binarną), jest czystym zbiegiem okoliczności.

 12
Author: weibeld,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-06 20:06:21

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 posiadanie kodowania podczas pracy z innymi środowiskami. Na przykład, jeśli używasz md5, otrzymasz różne wartości dla a i UA

 1
Author: Ali Rasim Kocal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-03 15:19:22