Najlepsza odpowiedź
Przepraszamy, nie ma prostej, jednowierszowej odpowiedzi na ten problem.
Wyobraź sobie, że ciąg znaków przychodzi do programu w Pythonie poprzez operację I / O (odczyt z terminala, pliku lub sieci), przemieszcza się po programie i jest kopiowany z miejsca na miejsce, i na koniec otrzymuje wyjście poprzez operację I / O. Na każdym etapie, jeśli przypiszesz unicode do str, „zobaczysz przerażający ascii codec can"t encode...
błąd. Niestety, nie ma prostego sposobu na naprawienie tego poza poprzez kod naprawiający wszystkie plamy.
Na przykład rozważ:
f\_in = open("filein.txt")
line = f\_in.read()
out\_msg = "The input line was: {line}".format(line=line)
f\_out = open("fileout.txt")
Jeśli nie wiesz, jakie kodowanie zostało użyte podczas zapisywania filein.txt, czeka Cię dziwne zachowanie i niektóre znaki w Twoim line
będą wyglądać jak śmieci. (Uwaga: wygrałeś ” t pojawia się błąd ascii codec can"t encode...
, ale mimo wszystko wyniki będą złe). Musisz więc użyć czegoś takiego jak: f\_in = codecs.open("filein.txt", "rb", "utf-8")
, a potem mieć rozpaczliwą nadzieję że ktokolwiek zapisał plik filein.txt, zapisał go w utf-8, a nie w jednym z innych kodowań UTF. (Uwaga: utf-8 jest kompatybilny w górę z ascii, więc plik, który był przechowywany przy użyciu zwykłego ascii, otworzy się dobrze przy użyciu kodowania utf-8).
Do tej pory oczywiście zdałeś sobie z tego sprawę, chyba że otwórz plik fileout.txt przy użyciu odpowiedniego kodowania Unicode, znowu będziesz miał kłopoty i pojawi się błąd ascii codec can"t encode...
(jeśli twój out\_msg zawiera jakikolwiek znak Unicode). Musisz więc zrobić codecs.open("fileout.txt", "wb", "utf-8")
. (Uwaga: użycie kodowania utf-8 do przechowywania zwykłego ascii nie stanowi problemu, ponieważ jest ono zgodne z poprzednimi wersjami, więc jeśli twój tekst nie zawiera znaków Unicode innych niż ASCII , plik zakodowany w utf-8 jest identyczny jak zwykły plik ascii.)
Zaskoczyło mnie to, że zrobienie tych dwóch rzeczy nie jest wystarczająco dobre. Rozważ ten zaktualizowany kod:
f\_in = codecs.open("filein.txt", "rb", "utf-8")
line = f\_in.read()
out\_msg = "The input line was: {line}".format(line=line)
f\_out = codecs.open("fileout.txt", "wb", "utf-8")
To nadal może powodować ten sam przerażający błąd w trzecim linia. To prawda, problem polega na tym, że "The input line was: {line}".format(xxx)"
to str
i jeśli line
zawiera wszelkie znaki Unicode (przez które mam na myśli znaki, których nie można zakodować w ascii), masz kłopoty.
Rozwiązanie:
out\_msg = u"The input line was: {line}".format(line=line)
(Tak, ta linia różni się od linii 3 w przykładowym kodzie. Musisz tylko uważnie się przyjrzeć.)
Więc to wszystko. Musisz przejść przez każdy wiersz kodu i znajdź miejsca, w których unicode jest przypisywany do str (lub jest wysyłany do metody, która oczekuje na str) i ustaw miejsce docelowe na unicode zamiast str.
Aby zrozumieć unicode w python lepiej, spójrz na: http://farmdev.com/thoughts/23/what-i-thought-i-knew-about-unicode-in-python-amounted-to-nothing/
Aby ogólnie zrozumieć Unicode (a ja bym bardzo zalecamy, abyś to zrobił) przeczytaj artykuł Joela Spolskyego „Absolutne minimum” Każdy programista absolutnie, pozytywnie musi wiedzieć o Unicode i zestawach znaków (Nie Wymówki!) „: http://www.joelonsoftware.com/articles/Unicode.html
A skoro już o tym mowa, równie dobrze możesz przeczytać: Jakie jest najlepsze źródło informacji o sprawdzonych metodach korzystania z Unicode w Pythonie?
Quick „n Brudny hack: Jeśli chcesz tylko wydrukować jakieś wyjście w przybliżonym ascii, możesz zrobić:
import unicodedata
line = unicodedata.normalize("NFKD", line).encode("ascii","ignore")
Spowoduje to zastąpienie wszystkich znaków innych niż ASCII najbliższym odpowiednikiem ascii lub po prostu zignorowanie znaku, jeśli nic nie jest odpowiednie . Jest wystarczająco dobry do wielu celów …
Odpowiedź
Powinieneś przekonwertować swoje łańcuchy Unicode (które składają się ze znaków, jednostki oddzielonej od rozmiaru pamięci) na bajty przy użyciu odpowiedniego kodowania przed wykonaniem z nim jakichkolwiek operacji we / wy.
Domyślnie Python próbuje zakodować ciąg znaków Unicode przy użyciu kodowania ASCII podczas zapisywania na standardowe wyjście (tj. za pomocą print ), ale to kodowanie nie może reprezentować każdego znaku Unicode, dlatego otrzymujesz ten błąd: kodek „ascii” nie może „zakodować znaku”. Dość wyraźne.
Powinieneś wybrać odpowiednie kodowanie i zakodować swój łańcuch Unicode używając go. Na przykład UTF-8 to wydajne kodowanie, które może obsłużyć każdy znak Unicode. Zakładając, że foo to ciąg znaków Unicode, możesz (i powinieneś) zrobić: print foo.encode („utf -8 „) zamiast tylko print foo . Po prostu upewnij się, że twój terminal lub cokolwiek rozumie wybrane przez ciebie kodowanie.Ponownie: UTF-8 jest najgorętszym kodowaniem w takich scenariuszach, prawdopodobnie będziesz chciał go użyć, chyba że masz bardzo konkretne potrzeby.