Głównym źródłem problemów, które miałem podczas pracy z ciągami znaków Unicode, jest mieszanie ciągów zakodowanych w utf-8 z ciągami znaków Unicode.
Na przykład rozważ następujące skrypty.
two.py
# encoding: utf-8
name = 'helló wörld from two'
one.py
# encoding: utf-8
from __future__ import unicode_literals
import two
name = 'helló wörld from one'
print name + two.name
Wynik działania python one.py
to:
Traceback (most recent call last):
File "one.py", line 5, in <module>
print name + two.name
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 4: ordinal not in range(128)
W tym przykładzie two.name
jest to ciąg zakodowany w formacie UTF-8 (nie Unicode), ponieważ nie został zaimportowany unicode_literals
, i one.name
jest to ciąg znaków Unicode. Kiedy mieszasz oba, Python próbuje zdekodować zakodowany ciąg (zakładając, że jest to ascii) i przekonwertować go na Unicode, ale kończy się to niepowodzeniem. Zadziałałoby, gdybyś to zrobił print name + two.name.decode('utf-8')
.
To samo może się zdarzyć, jeśli zakodujesz ciąg i spróbujesz go później zmiksować. Na przykład to działa:
# encoding: utf-8
html = '<html><body>helló wörld</body></html>'
if isinstance(html, unicode):
html = html.encode('utf-8')
print 'DEBUG: %s' % html
Wynik:
DEBUG: <html><body>helló wörld</body></html>
Ale po dodaniu import unicode_literals
NIE:
# encoding: utf-8
from __future__ import unicode_literals
html = '<html><body>helló wörld</body></html>'
if isinstance(html, unicode):
html = html.encode('utf-8')
print 'DEBUG: %s' % html
Wynik:
Traceback (most recent call last):
File "test.py", line 6, in <module>
print 'DEBUG: %s' % html
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 16: ordinal not in range(128)
Nie udaje się, ponieważ 'DEBUG: %s'
jest to ciąg znaków Unicode i dlatego Python próbuje zdekodować html
. Kilka sposobów na naprawienie wydruku to robi print str('DEBUG: %s') % html
lub print 'DEBUG: %s' % html.decode('utf-8')
.
Mam nadzieję, że pomoże ci to zrozumieć potencjalne problemy podczas używania ciągów Unicode.
decode()
rozwiązania zamiast rozwiązaństr()
lubencode()
: im częściej używasz obiektów Unicode, tym jaśniejszy jest kod, ponieważ to, czego chcesz, to manipulowanie ciągami znaków, a nie tablicami bajtów z zewnętrznie implikowanym kodowaniem.when you mix utf-8 encoded strings with unicode ones
UTF-8 i Unicode mają dwa różne kodowania; Unicode jest standardem, a UTF-8 jest jednym z kodowań, które definiuje.str
, drugie jest typemunicode
. Będąc różnymi obiektami, problem może się pojawić, jeśli spróbujesz je zsumować /python>=2.6
lubpython==2.6
?Również w 2.6 (przed Pythonem 2.6.5 RC1 +) literały Unicode nie działają dobrze z argumentami słów kluczowych ( problem4978 ):
Na przykład poniższy kod działa bez unicode_literals, ale kończy się niepowodzeniem z TypeError:
keywords must be string
jeśli jest używany unicode_literals.źródło
Zauważyłem, że jeśli dodasz
unicode_literals
dyrektywę, powinieneś również dodać coś takiego:do pierwszej lub drugiej linii pliku .py. W przeciwnym razie linie takie jak:
powoduje błąd, taki jak:
źródło
# -*- coding: utf-8
jest praktycznie obowiązkowym oświadczeniem, niezależnie od tego, czy używasz,unicode_literals
czy nie-*-
jest wymagane; jeśli wybierasz sposób zgodny z emacsem, myślę, że będziesz potrzebować-*- encoding: utf-8 -*-
(zobacz również-*-
na końcu). Wszystko, czego potrzebujesz, tocoding: utf-8
(lub nawet=
zamiast:
).from __future__ import unicode_literals
.# -*- coding: utf-8 -*-
„kodowania” (nie „kodowania”, „kodowania plików” ani czegokolwiek innego - Python po prostu szuka „kodowania” bez względu na prefiks).Weź również pod uwagę, że
unicode_literal
wpłynie,eval()
ale nierepr()
(asymetryczne zachowanie, które imho jest błędem), tj.eval(repr(b'\xa4'))
Nie będzie równeb'\xa4'
(tak jak w przypadku Pythona 3).Idealnie byłoby, gdyby poniższy kod był niezmiennikiem, który zawsze powinien działać dla wszystkich kombinacji
unicode_literals
i użycia Pythona {2.7, 3.x}:Drugie twierdzenie dzieje się z pracy, ponieważ
repr('\xa4')
ma wartośću'\xa4'
w Pythonie 2.7.źródło
repr
do regeneracji obiektu.repr
Dokumentacja wyraźnie stwierdza, że to nie wymóg. Moim zdaniem sprowadza się torepr
do czegoś przydatnego tylko do debugowania.Jest ich więcej.
Istnieją biblioteki i elementy wbudowane, które oczekują ciągów znaków, które nie tolerują kodu Unicode.
Dwa przykłady:
wbudowany:
(nieco esotyczny) nie działa z unicode_literals: type () oczekuje łańcucha.
biblioteka:
nie działa: biblioteka wx pubsub oczekuje komunikatu typu string.
Ten pierwszy jest ezoteryczny i można go łatwo naprawić
ale to drugie jest druzgocące, jeśli twój kod jest pełen wywołań funkcji pub.sendMessage () (czyli mojego).
Cholera, co?!?
źródło
class Meta:
powinny byćb'field_name'
Kliknięcie podniesie wyjątki Unicode w każdym miejscu, jeśli jakikolwiek moduł, który został
from __future__ import unicode_literals
zaimportowany, gdzie używaszclick.echo
. To koszmar…źródło