Jak obejít chybu Pythonu ' UnicodeEncodeError: ' ascii ' kodek nemůže kódovat znak … ' při použití skriptu Pythonu na příkazovém řádku


nejlepší odpověď

Omlouváme se, na tento problém neexistuje jednoduchá jednorázová odpověď.

Představte si, že řetězec aa přichází do pythonovského programu prostřednictvím operace I / O (čtení z terminálu nebo ze souboru nebo ze sítě), prochází si program kopírováním z místa na místo, a nakonec dostane výstup přes I / O operaci. Pokud v libovolném kroku přiřadíte strunu unicode, uvidíte „obávanou ascii codec can"t encode... chybu. Bohužel neexistuje snadný způsob, jak to opravit, než jít prostřednictvím kódu opravujícího všechna místa.

Například zvažte:

f\_in = open("filein.txt")

line = f\_in.read()

out\_msg = "The input line was: {line}".format(line=line)

f\_out = open("fileout.txt")

Pokud nevíte, jaké kódování bylo použito při ukládání souboru filein.txt, čeká vás bizarní chování a některé znaky ve vašem line budou vypadat jako smetí. (Poznámka: vyhráli jste) Nechci dostat chybu ascii codec can"t encode..., ale výsledky budou přesto špatné.) Takže musíte použít něco jako: f\_in = codecs.open("filein.txt", "rb", "utf-8") a pak zoufale doufat že kdokoli uložil soubor filein.txt, uložil jej do utf-8 a ne do jednoho z dalších kódování UTF. (Poznámka: utf-8 je směrem nahoru kompatibilní s ascii, takže soubor, který byl uložen pomocí běžného ascii, se bude dobře otevírat pomocí kódování utf-8).

Nyní si samozřejmě uvědomujete, že pokud otevřete souboroutout.txt pomocí vhodného kódování unicode, znovu narazíte na potíže a dostanete chybu ascii codec can"t encode... (pokud váš out\_msg obsahuje jakýkoli znak unicode). Musíte tedy udělat codecs.open("fileout.txt", "wb", "utf-8"). (Všimněte si znovu: použití kódování utf-8 k ukládání běžného ascii není problém, protože je kompatibilní s vyšší verzí, takže pokud váš text neobsahuje znaky unicode jiné než ascii , soubor kódovaný v utf-8 je totožný s běžným souborem ascii.)

Věc, která mě spustila, byla, že dělat tyto dvě věci není dost dobré. Zvažte tento aktualizovaný kód:

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 by vám na třetím mohlo stále způsobit stejnou obávanou chybu čára. Máte pravdu, problém spočívá v tom, že "The input line was: {line}".format(xxx)" je str a pokud line obsahuje jakékoli znaky Unicode (čímž myslím znaky, které nelze kódovat do ASCII) máte potíže.

Oprava tohoto problému je:

out\_msg = u"The input line was: {line}".format(line=line)

(Ano, tento řádek se liší od řádku 3 v ukázce kódu. Musíte se jen pečlivě podívat.)

Takže tady to máte. Musíte projít každý řádek kódu a najděte místa, kde je unicode přiřazen str (nebo je odeslán metodě, která očekává str) a opravte cíl tak, aby byl unicode místo str.

Pochopení unicode v Python lépe, podívejte se na: http://farmdev.com/thoughts/23/what-i-thought-i-knew-about-unicode-in-python-amounted-to-nothing/

Chcete-li pochopit unicode obecně (a já bych velmi doporučujeme, abyste to udělali) číst „Joel Spolsky“ Absolutní minimum Každý vývojář softwaru absolutně, pozitivně musí vědět o sadách Unicode a znakech (ne Omlouváme se!) „: http://www.joelonsoftware.com/articles/Unicode.html

A když už jste o tom, můžete si přečíst: Jaký je nejlepší zdroj informací o doporučených postupech unicode v pythonu?

Rychlý „n Špinavý hack: Pokud si jen chcete nechat vytisknout nějaký výstup v přibližném formátu ascii, můžete to udělat:

import unicodedata

line = unicodedata.normalize("NFKD", line).encode("ascii","ignore")

Tím nahradíte všechny znaky jiné než ascii nejbližším ekvivalentem ascii, nebo prostě ignorujete znak, pokud nic není vhodné . Je to dost dobré pro mnoho účelů …

Odpověď

Řetězce Unicode (které jsou tvořeny znaky, jednotkou oddělenou od velikosti paměti) byste měli převést na bajty pomocí správného kódování předtím, než s ním provedete jakýkoli vstup / výstup.

Ve výchozím nastavení se Python pokouší při zápisu na stdout kódovat řetězec Unicode pomocí kódování ASCII (tj. pomocí tisk ), ale toto kódování nemůže představovat každý znak Unicode, proto se vám zobrazuje tato chyba: kodek „ascii“ nemůže „kódovat znak“. Docela explicitní.

Měli byste zvolit správné kódování a pomocí toho zakódovat řetězec Unicode. Například UTF-8 je efektivní kódování, které zvládne každý znak Unicode. Za předpokladu, že foo je řetězec Unicode, můžete (a měli byste) udělat: vytisknout foo.encode („utf -8 „) namísto pouze print foo . Jen se ujistěte, že váš terminál nebo cokoli rozumí vybranému kódování.Opět: UTF-8 je nejžhavější kódování pro scénáře, jako je tento, pravděpodobně ho budete chtít použít, pokud nemáte velmi specifické potřeby.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *