Hoe de Python-fout te omzeilen ' UnicodeEncodeError: ' ascii ' codec kan karakter niet coderen … ' bij gebruik van een Python-script op de opdrachtregel


Beste antwoord

Sorry, er is geen eenvoudig eenregelig antwoord op dit probleem.

Stel je voor dat een string in een Python-programma komt via een I / O-bewerking (gelezen van terminal, of van bestand, of van het netwerk), het baant zich een weg door het programma en wordt van plaats naar plaats gekopieerd, en tenslotte krijgt het output via een I / O-bewerking. Als u bij elke stap een unicode aan een str toewijst, “ziet u de gevreesde ascii codec can"t encode... -fout. Helaas is er geen gemakkelijke manier om dit op te lossen, behalve door te gaan door uw code die alle vlekken herstelt.

Overweeg bijvoorbeeld:

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

line = f\_in.read()

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

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

Tenzij je weet welke codering werd gebruikt bij het opslaan van filein.txt, sta je voor bizar gedrag en zullen sommige karakters in je line eruitzien als rotzooi. (Opmerking: je hebt gewonnen ” krijg de ascii codec can"t encode... -fout, maar de resultaten zullen desalniettemin slecht zijn.) Dus je moet zoiets gebruiken als: f\_in = codecs.open("filein.txt", "rb", "utf-8") en dan wanhopig hopen dat degene die filein.txt had opgeslagen het in utf-8 had opgeslagen en niet in een van de andere UTF-coderingen. (Opmerking: utf-8 is opwaarts compatibel met ascii, dus een bestand dat is opgeslagen met gewone ascii zal prima openen met utf-8-codering).

Inmiddels zul je je duidelijk hebben gerealiseerd dat, tenzij je open fileout.txt met een geschikte Unicode-codering, zul je opnieuw in de problemen komen en de ascii codec can"t encode... -fout krijgen (als je out\_msg een Unicode-teken bevat). Dus je moet codecs.open("fileout.txt", "wb", "utf-8"). (Nogmaals: het gebruik van een utf-8-codering om gewone ascii op te slaan is geen probleem, aangezien het opwaarts compatibel is, dus als uw tekst geen niet-ascii-unicode-tekens bevat , het utf-8-gecodeerde bestand is identiek aan een gewoon ascii-bestand.)

Wat me in de war bracht, was dat het doen van deze twee dingen niet goed genoeg is. Beschouw deze bijgewerkte code:

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")

Dit zou je nog steeds dezelfde gevreesde fout kunnen geven op de derde lijn. Dat klopt, het probleem is dat "The input line was: {line}".format(xxx)" een str is en als line alle unicode-tekens (waarmee ik tekens bedoel die niet in ascii kunnen worden gecodeerd) u in de problemen zit.

De oplossing hiervoor is:

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

(Ja, deze regel verschilt van regel 3 in het codevoorbeeld. Je moet gewoon goed kijken.)

Dus daar heb je het. Moet doorlopen elke regel van uw code en vind plaatsen waar unicode wordt toegewezen aan str (of wordt verzonden naar een methode die een str verwacht) en repareer de bestemming als unicode in plaats van str.

Unicode begrijpen in python beter, kijk eens naar: http://farmdev.com/thoughts/23/what-i-thought-i-knew-about-unicode-in-python-amounted-to-nothing/

Om unicode in het algemeen te begrijpen (en ik zou zeer raden u aan dit te doen) lees Joel Spolsky s Het absolute minimum dat elke softwareontwikkelaar absoluut en positief moet weten over Unicode en tekensets (nee Excuses!) “: http://www.joelonsoftware.com/articles/Unicode.html

En terwijl je het erover hebt, kun je net zo goed lezen: wat is de beste bron om meer te weten te komen over praktische tips voor Unicode in python?

Quick “n Dirty Hack: Als je gewoon wat uitvoer wilt laten afdrukken in geschatte ascii, kun je het volgende doen:

import unicodedata

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

Dit zal alle niet-ascii-tekens vervangen door het dichtstbijzijnde ascii-equivalent, of het teken negeren als niets geschikt is . Is goed genoeg voor vele doeleinden …

Antwoord

U moet uw Unicode-strings (die zijn gemaakt van tekens, een eenheid die is ontkoppeld van de geheugengrootte) converteren naar bytes met de juiste codering voordat je er I / O mee doet.

Standaard probeert Python je Unicode-string te coderen met behulp van de ASCII-codering bij het schrijven naar stdout (dwz met print ), maar deze codering kan “niet elk Unicode-teken vertegenwoordigen, daarom krijg je die foutmelding:” “ascii” codec kan “t coderen karakter”. Vrij expliciet.

Je zou een goede codering moeten kiezen, en daarmee je Unicode-string coderen. UTF-8 is bijvoorbeeld een efficiënte codering die elk Unicode-teken aankan. Ervan uitgaande dat foo een Unicode-string is, zou je kunnen (en zou moeten) doen: print foo.encode (“utf -8 “) in plaats van alleen print foo . Zorg ervoor dat uw terminal of wat dan ook de codering die u kiest, begrijpt.Nogmaals: UTF-8 is de meest populaire codering die er is voor scenarios als deze, je zult het waarschijnlijk willen gebruiken tenzij je heel specifieke behoeften hebt.

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *