Hur man kommer runt Python-felet ' UnicodeEncodeError: ' ascii ' codec kan inte koda tecken … ' när du använder ett Python-skript på kommandoraden


Bästa svaret

Tyvärr finns det inget enkelt svar på en rad på det här problemet.

Föreställ dig att en sträng kommer in i ett pythonprogram via en I / O-operation (läst från terminal eller från fil eller från nätverket), den tar sig runt programmet och kopieras från plats till plats, och slutligen får den ut via en I / O-operation. I vilket steg som helst, om du tilldelar en unicode till en str, ser du det fruktade ascii codec can"t encode... -felet. Tyvärr finns det inget enkelt sätt att fixa det annat än att gå genom din kod som fixar alla fläckar.

Tänk till exempel:

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

line = f\_in.read()

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

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

Om du inte vet vilken kodning som användes vid lagring av filein.txt, är du inne på något bisarrt beteende och några tecken i din line kommer att se ut som skräp. t få felet ascii codec can"t encode..., men resultaten blir ändå dåliga.) Så du måste använda något som: f\_in = codecs.open("filein.txt", "rb", "utf-8") och sedan hoppas desperat att den som lagrade filein.txt hade lagrat den i utf-8 och inte någon av de andra UTF-kodningarna. (Obs: utf-8 är uppåt kompatibel med ascii, så en fil som lagrades med vanlig ascii öppnas bra med utf-8-kodning).

Nu har du självklart insett att om du inte öppna fileout.txt med en lämplig unicode-kodning, du kommer åter att stöta på problem och få ascii codec can"t encode... -felet (om din out\_msg innehåller något unicode-tecken). Så du måste göra codecs.open("fileout.txt", "wb", "utf-8"). (Obs igen: att använda en utf-8-kodning för att lagra vanligt ASCII är inte ett problem, eftersom det är uppåtkompatibelt, så om din text inte innehåller icke-ASCII-unicode-tecken , den utf-8-kodade filen är identisk med en vanlig ascii-fil.)

Det som snubblade mig var att det inte är tillräckligt att göra dessa två saker. Tänk på den här uppdaterade koden:

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

Detta kan fortfarande ge dig samma fruktade fel den tredje linje. Det är rätt, problemet är att "The input line was: {line}".format(xxx)" är en str och om line innehåller alla unicode-tecken (med vilka jag menar tecken som inte kan kodas till ascii) du är i trubbel.

Korrigeringen för det är:

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

(Ja, den här raden skiljer sig från rad 3 i kodprovet. Du måste bara titta noga.)

Så där har du det. Behöver gå igenom varje rad i din kod och hitta platser där unicode tilldelas str (eller skickas till en metod som förväntar sig en str) och fixa destinationen som unicode istället för str.

Att förstå unicode i python bättre, ta en titt på: http://farmdev.com/thoughts/23/what-i-thought-i-knew-about-unicode-in-python-amounted-to-nothing/

För att förstå unicode i allmänhet (och jag skulle mycket rekommenderar att du gör detta) läs Joel Spolsky ”s” The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Ursäkter!) ”: http://www.joelonsoftware.com/articles/Unicode.html

Och medan du handlar om det kan du lika gärna läsa: Vad är den bästa källan för att lära dig mer om unicodes bästa praxis i python?

Snabb ”n Dirty Hack: Om du bara vill trycka lite utskrifter i ungefärliga askor kan du göra:

import unicodedata

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

Detta ersätter alla icke-ascii-tecken med den närmaste ascii-ekvivalenten, eller ignorerar bara tecknet om inget är lämpligt . Är tillräckligt bra för många ändamål …

Svar

Du bör konvertera dina Unicode-strängar (som är gjorda av tecken, en enhet frikopplad från minnesstorlek) till byte med rätt kodning innan du gör någon I / O med den.

Som standard försöker Python koda din Unicode-sträng med ASCII-kodningen när du skriver till stdout (dvs. använder skriva ut ), men den här kodningen kan inte representera varje Unicode-tecken, varför du får det felet: ”” ascii ”codec kan inte koda tecken”. Ganska tydligt.

Du bör välja en korrekt kodning och koda din Unicode-sträng med den. Till exempel är UTF-8 en effektiv kodning som kan hantera alla Unicode-tecken. Förutsatt att foo är en Unicode-sträng kan du (och borde) göra: skriva ut foo.encode (”utf -8 ”) istället för bara skriv ut foo . Se bara till att din terminal eller vad som än förstår kodningen du väljer.Återigen: UTF-8 är den hetaste kodningen där ute för sådana scenarier, du kommer antagligen vilja använda den om du inte har mycket specifika behov.

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *