tl; dr / szybka poprawka
- Nie dekoduj / koduj willy nilly
- Nie zakładaj, że twoje łańcuchy są zakodowane w UTF-8
- Spróbuj przekonwertować ciągi znaków na ciągi Unicode tak szybko, jak to możliwe w kodzie
- Napraw swoje ustawienia regionalne: jak rozwiązać UnicodeDecodeError w Pythonie 3.6?
- Nie ulegaj pokusie używania szybkich
reload
hacków
Unicode Zen w Python 2.x - wersja długa
Nie widząc źródła trudno jest poznać przyczynę, więc będę musiał mówić ogólnie.
UnicodeDecodeError: 'ascii' codec can't decode byte
zazwyczaj dzieje się, gdy próbujesz przekonwertować Python 2.x, str
który zawiera nie-ASCII na ciąg Unicode, bez określania kodowania oryginalnego ciągu.
W skrócie, ciągi Unicode są całkowicie oddzielnym typem ciągów Python, które nie zawierają żadnego kodowania. Przechowują tylko kody punktowe Unicode i dlatego mogą przechowywać dowolny punkt Unicode z całego spektrum. Ciągi zawierają zakodowany tekst, jednak UTF-8, UTF-16, ISO-8895-1, GBK, Big5 itp. Ciągi są dekodowane do Unicode, a Unicode są kodowane do ciągów . Pliki i dane tekstowe są zawsze przesyłane w zakodowanych ciągach.
Autorzy modułu Markdown prawdopodobnie używają unicode()
(gdzie zgłaszany jest wyjątek) jako jakościowej bramki do reszty kodu - przekonwertuje ASCII lub ponownie zawinie istniejące ciągi Unicode na nowy ciąg Unicode. Autorzy Markdown nie znają kodowania przychodzącego łańcucha, więc będą polegać na tobie, aby zdekodować łańcuchy na łańcuchy Unicode przed przekazaniem do Markdown.
Ciągi znaków Unicode można zadeklarować w kodzie za pomocą u
przedrostka ciągów znaków. Na przykład
>>> my_u = u'my ünicôdé strįng'
>>> type(my_u)
<type 'unicode'>
Ciągi znaków Unicode mogą również pochodzić z plików, baz danych i modułów sieciowych. Kiedy tak się dzieje, nie musisz się martwić o kodowanie.
Gotchas
Konwersja z str
na Unicode może się zdarzyć, nawet jeśli nie zadzwonisz jawnie unicode()
.
Następujące scenariusze powodują UnicodeDecodeError
wyjątki:
# Explicit conversion without encoding
unicode('€')
# New style format string into Unicode string
# Python will try to convert value string to Unicode first
u"The currency is: {}".format('€')
# Old style format string into Unicode string
# Python will try to convert value string to Unicode first
u'The currency is: %s' % '€'
# Append string to Unicode
# Python will try to convert string to Unicode first
u'The currency is: ' + '€'
Przykłady
Na poniższym diagramie można zobaczyć, jak słowo café
zostało zakodowane w kodowaniu „UTF-8” lub „Cp1252” w zależności od typu terminala. W obu przykładach caf
jest po prostu zwykłym ascii. W UTF-8 é
jest kodowany przy użyciu dwóch bajtów. W „Cp1252” é ma wartość 0xE9 (która jest również wartością punktową Unicode (to nie przypadek)). Wywoływane decode()
jest prawidłowe i konwersja na kodowanie Unicode w języku Python kończy się powodzeniem:
Na tym schemacie decode()
jest wywoływany za pomocą ascii
(co jest takie samo jak wywoływanie unicode()
bez podanego kodowania). Ponieważ ASCII nie może zawierać bajtów większych niż 0x7F
, spowoduje to UnicodeDecodeError
wyjątek:
Kanapka Unicode
Dobrą praktyką jest tworzenie w kodzie kanapki Unicode, w której dekodujesz wszystkie przychodzące dane do ciągów Unicode, pracujesz z Unicodes, a następnie kodujesz do str
s po wyjściu. Dzięki temu nie musisz się martwić kodowaniem ciągów znaków w środku kodu.
Wejście / dekodowanie
Kod źródłowy
Jeśli chcesz upiec kod inny niż ASCII w kodzie źródłowym, po prostu utwórz ciągi Unicode, poprzedzając je ciągiem u
. Na przykład
u'Zürich'
Aby umożliwić Pythonowi zdekodowanie kodu źródłowego, musisz dodać nagłówek kodowania zgodny z faktycznym kodowaniem pliku. Na przykład, jeśli plik został zakodowany jako „UTF-8”, użyłbyś:
# encoding: utf-8
Jest to konieczne tylko wtedy, gdy masz kod inny niż ASCII w kodzie źródłowym .
Akta
Zazwyczaj dane spoza ASCII są odbierane z pliku. io
Moduł dostarcza TextWrapper który dekoduje plik na bieżąco, za pomocą danego encoding
. Musisz użyć prawidłowego kodowania pliku - nie można go łatwo odgadnąć. Na przykład dla pliku UTF-8:
import io
with io.open("my_utf8_file.txt", "r", encoding="utf-8") as my_file:
my_unicode_string = my_file.read()
my_unicode_string
byłby wtedy odpowiedni do przejścia do Markdown. Jeśli UnicodeDecodeError
pochodzi z read()
linii, prawdopodobnie użyłeś niewłaściwej wartości kodowania.
Pliki CSV
Moduł CSV Python 2.7 nie obsługuje znaków spoza ASCII 😩. Pomoc jest jednak pod ręką dzięki https://pypi.python.org/pypi/backports.csv .
Użyj go jak wyżej, ale przekaż do niego otwarty plik:
from backports import csv
import io
with io.open("my_utf8_file.txt", "r", encoding="utf-8") as my_file:
for row in csv.reader(my_file):
yield row
Bazy danych
Większość sterowników baz danych Python może zwracać dane w formacie Unicode, ale zwykle wymaga niewielkiej konfiguracji. Zawsze używaj ciągów Unicode do zapytań SQL.
MySQL
W ciągu połączenia dodaj:
charset='utf8',
use_unicode=True
Na przykład
>>> db = MySQLdb.connect(host="localhost", user='root', passwd='passwd', db='sandbox', use_unicode=True, charset="utf8")
PostgreSQL
Dodaj:
psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
psycopg2.extensions.register_type(psycopg2.extensions.UNICODEARRAY)
HTTP
Strony internetowe można zakodować niemal w dowolnym kodowaniu. Content-type
Nagłówek powinien zawierać charset
pole, aby schować w kodowaniu. Zawartość można następnie dekodować ręcznie w oparciu o tę wartość. Alternatywnie, Python-Requests zwraca Unicode w response.text
.
Ręcznie
Jeśli musisz ręcznie dekodować ciągi, możesz po prostu zrobić my_string.decode(encoding)
, gdzie encoding
jest odpowiednie kodowanie. Podano tutaj kodeki obsługiwane w języku Python 2.x: Standardowe kodowanie . Ponownie, jeśli UnicodeDecodeError
to zrobisz, prawdopodobnie masz złe kodowanie.
Mięso Kanapki
Pracuj z Unicodes tak jak normalne napisy.
Wynik
standardowe / drukowanie
print
zapisuje przez standardowy strumień. Python próbuje skonfigurować koder na standardowym wyjściu, aby Unicode były kodowane do kodowania konsoli. Na przykład, jeśli Linux powłoki na locale
to en_GB.UTF-8
, wyjście zostanie zakodowany UTF-8
. W systemie Windows będziesz ograniczony do 8-bitowej strony kodowej.
Niepoprawnie skonfigurowana konsola, na przykład uszkodzone ustawienia regionalne, może prowadzić do nieoczekiwanych błędów drukowania. PYTHONIOENCODING
zmienna środowiskowa może wymusić kodowanie dla standardowego wyjścia.
Akta
Podobnie jak dane wejściowe, io.open
może służyć do przezroczystej konwersji Unicodów na zakodowane ciągi bajtów.
Baza danych
Ta sama konfiguracja odczytu pozwoli na bezpośrednie pisanie Unicodów.
Python 3
Python 3 nie obsługuje bardziej Unicode niż Python 2.x, jednak jest nieco mniej zdezorientowany w tym temacie. Np. Regular str
jest teraz ciągiem Unicode, a stary str
jest teraz bytes
.
Domyślne kodowanie to UTF-8, więc jeśli .decode()
ciąg bajtów nie został podany, Python 3 używa kodowania UTF-8. Prawdopodobnie rozwiązuje to 50% problemów z Unicode.
Ponadto open()
domyślnie działa w trybie tekstowym, więc zwraca zdekodowane str
(Unicode). Kodowanie pochodzi z ustawień regionalnych, które zwykle mają postać UTF-8 w systemach Un * x lub 8-bitową stronę kodową, taką jak Windows-1251, w polach Windows.
Dlaczego nie powinieneś używać sys.setdefaultencoding('utf8')
To paskudny hack (jest powód, dla którego musisz go użyć reload
), który tylko maskuje problemy i utrudnia migrację do Pythona 3.x. Zrozum problem, napraw główną przyczynę i ciesz się zen z Unicode. Zobacz, dlaczego NIE powinniśmy używać sys.setdefaultencoding („utf-8”) w skrypcie py? dla dalszych szczegółów