Oplossen: UnicodeDecodeError: ‘ascii’ codec kan byte niet decoderen

Hoe dit op te lossen?

In sommige andere op Python gebaseerde statische blog-apps kunnen Chinese berichten met succes worden gepubliceerd.
Zoals deze app: http://github.com/vrypan/bucket3. Op mijn site http://bc3.brite.biz/ kan Chinese post met succes worden gepubliceerd.


Antwoord 1, autoriteit 100%

tl;dr / snelle oplossing

  • Niet willy nilly decoderen/coderen
  • Ga er niet vanuit dat uw strings UTF-8-gecodeerd zijn
  • Probeer tekenreeksen zo snel mogelijk in uw code om te zetten naar Unicode-tekenreeksen
  • Corrigeer uw landinstelling: Hoe UnicodeDecodeError op te lossen in Python 3.6?
  • Laat u niet verleiden om snelle reload-hacks te gebruiken

Unicode Zen in Python 2.x – De lange versie

Zonder de bron te zien is het moeilijk om de oorzaak te achterhalen, dus ik zal in het algemeen moeten spreken.

UnicodeDecodeError: 'ascii' codec can't decode byte gebeurt meestal wanneer u een Python 2.x str die niet-ASCII bevat, probeert te converteren naar een Unicode-tekenreeks zonder de codering van de originele string op te geven.

Kortom, Unicode-tekenreeksen zijn een volledig apart type Python-tekenreeks die geen codering bevat. Ze bevatten alleen Unicode puntcodes en kunnen daarom elk Unicode-punt uit het hele spectrum bevatten. Strings bevatten gecodeerde tekst, zoals UTF-8, UTF-16, ISO-8895-1, GBK, Big5 enz. Strings worden gedecodeerd naar Unicode en Unicodes worden gecodeerd naar strings . Bestanden en tekstgegevens worden altijd in gecodeerde tekenreeksen overgedragen.

De auteurs van de Markdown-module gebruiken waarschijnlijk unicode() (waar de uitzondering wordt gegenereerd) als kwaliteitspoort voor de rest van de code – het converteert ASCII of herpakt bestaande Unicodes-strings naar een nieuwe Unicode-tekenreeks. De Markdown-auteurs kunnen de codering van de inkomende tekenreeks niet kennen, dus zullen ze erop vertrouwen dat u tekenreeksen naar Unicode-tekenreeksen decodeert voordat ze naar Markdown gaan.

Unicode-tekenreeksen kunnen in uw code worden gedeclareerd met het u-voorvoegsel voor tekenreeksen. Bijv.

>>> my_u = u'my unicode string'
>>> type(my_u)
<type 'unicode'>

Unicode-strings kunnen ook afkomstig zijn van bestanden, databases en netwerkmodules. Wanneer dit gebeurt, hoeft u zich geen zorgen te maken over de codering.

Gekregen

Conversie van str naar Unicode kan zelfs plaatsvinden als u unicode() niet expliciet aanroept.

De volgende scenario’s veroorzaken UnicodeDecodeError uitzonderingen:

# 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: ' + '€'         

Voorbeelden

In het volgende diagram kunt u zien hoe het woord cafe is gecodeerd in de codering “UTF-8” of “Cp1252”, afhankelijk van het terminaltype. In beide voorbeelden is caf gewoon gewone ascii. In UTF-8 wordt e gecodeerd met twee bytes. In “Cp1252” is e 0xE9 (wat toevallig ook de Unicode-puntwaarde is (het is geen toeval)). De juiste decode() wordt aangeroepen en de conversie naar een Python Unicode is geslaagd:
Diagram van een tekenreeks die wordt geconverteerd naar een Python Unicode-tekenreeks

In dit diagram wordt decode() aangeroepen met ascii (wat hetzelfde is als unicode() aanroepen zonder een codering gegeven) . Aangezien ASCII geen bytes groter dan 0x7F kan bevatten, wordt er een UnicodeDecodeError-uitzondering gegenereerd:

Diagram van een string die wordt geconverteerd naar een Python Unicode-string met de verkeerde codering

De Unicode Sandwich

Het is een goede gewoonte om een ​​Unicode-sandwich in uw code te vormen, waarin u alle binnenkomende gegevens decodeert naar Unicode-strings, met Unicodes werkt en vervolgens codeert naar strs op de weg naar buiten. Dit voorkomt dat u zich zorgen hoeft te maken over de codering van strings in het midden van uw code.

Invoeren / decoderen

Broncode

Als u niet-ASCII in uw broncode wilt opnemen, maakt u gewoon Unicode-tekenreeksen door de tekenreeks te laten voorafgaan door een u. Bijv.

u'Zurich'

Om Python je broncode te laten decoderen, moet je een coderingsheader toevoegen die overeenkomt met de daadwerkelijke codering van je bestand. Als uw bestand bijvoorbeeld is gecodeerd als ‘UTF-8’, gebruikt u:

# encoding: utf-8

Dit is alleen nodig als je niet-ASCII in je broncode hebt.

Bestanden

Meestal worden niet-ASCII-gegevens uit een bestand ontvangen. De module io biedt een TextWrapper die uw bestand on-the-fly decodeert, met behulp van een bepaalde encoding. U moet de juiste codering voor het bestand gebruiken – het kan niet gemakkelijk worden geraden. Bijvoorbeeld voor een UTF-8-bestand:

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 zou dan geschikt zijn om door te geven aan Markdown. Als een UnicodeDecodeError van de read() regel, dan heb je waarschijnlijk de verkeerde coderingswaarde gebruikt.

CSV-bestanden

De Python 2.7 CSV-module ondersteunt geen niet-ASCII-tekens ??. Er is echter hulp bij de hand met https://pypi.python.org/pypi/backports.csv .

Gebruik het zoals hierboven, maar geef het geopende bestand eraan door:

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

Databases

De meeste Python-databasestuurprogramma’s kunnen gegevens retourneren in Unicode, maar vereisen meestal een kleine configuratie. Gebruik altijd Unicode-tekenreeksen voor SQL-query’s.

MySQL

Voeg in de verbindingsreeks toe:

charset='utf8',
use_unicode=True

Bijvoorbeeld

>>> db = MySQLdb.connect(host="localhost", user='root', passwd='passwd', db='sandbox', use_unicode=True, charset="utf8")

PostgreSQL

Toevoegen:

psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
psycopg2.extensions.register_type(psycopg2.extensions.UNICODEARRAY)

HTTP

Webpagina’s kunnen in vrijwel elke codering worden gecodeerd. De kop Content-type moet een veld charset bevatten om te verwijzen naar de codering. De inhoud kan vervolgens handmatig worden gedecodeerd tegen deze waarde. Als alternatief retourneert Python-Requests Unicodes in response.text.

Handmatig

Als je strings handmatig moet decoderen, kun je eenvoudig my_string.decode(encoding) doen, waarbij encoding de juiste codering is. Door Python 2.x ondersteunde codecs worden hier gegeven: Standaard Coderingen. Nogmaals, als je UnicodeDecodeError krijgt, heb je waarschijnlijk de verkeerde codering.

Het vlees van de sandwich

Werk met Unicodes zoals u normaal zou doen.

Uitvoer

stdout / afdrukken

print schrijft via de stdout-stream. Python probeert een encoder op stdout te configureren zodat Unicodes worden gecodeerd naar de codering van de console. Als de locale van een Linux-shell bijvoorbeeld en_GB.UTF-8 is, wordt de uitvoer gecodeerd naar UTF-8. In Windows bent u beperkt tot een 8-bits codepagina.

Een onjuist geconfigureerde console, zoals een corrupte landinstelling, kan leiden tot onverwachte afdrukfouten. PYTHONIOENCODING omgevingsvariabele kan de codering forceren voor stdout.

Bestanden

Net als invoer kan io.open worden gebruikt om Unicodes transparant te converteren naar gecodeerde byte-strings.

Database

Met dezelfde configuratie voor lezen kunnen Unicodes direct worden geschreven.

Python 3

Python 3 is niet meer geschikt voor Unicode dan Python 2.x, maar het is iets minder verward over het onderwerp. De gewone str is nu bijvoorbeeld een Unicode-tekenreeks en de oude str is nu bytes.

De standaardcodering is UTF-8, dus als u .decode() een bytetekenreeks gebruikt zonder een codering op te geven, gebruikt Python 3 UTF-8-codering. Dit lost waarschijnlijk 50% van de Unicode-problemen van mensen op.

Verder werkt open() standaard in tekstmodus, dus retourneert gedecodeerde str (Unicode-eenheden). De codering is afgeleid van uw landinstelling, die meestal UTF-8 is op Un*x-systemen of een 8-bits codepagina, zoals windows-1251, op Windows-boxen.

Waarom u sys.setdefaultencoding('utf8')

niet moet gebruiken

Het is een vervelende hack (er is een reden waarom je reload moet gebruiken) die alleen problemen maskeert en je migratie naar Python 3.x verhindert. Begrijp het probleem, verhelp de oorzaak en geniet van Unicode zen.
Zie Waarom zouden we NIET sys.setdefaultencoding(“utf-8”) gebruiken in een py-script? voor meer details


Antwoord 2, autoriteit 81%

Eindelijk snap ik het:

as3:/usr/local/lib/python2.7/site-packages# cat sitecustomize.py
# encoding=utf8  
import sys  
reload(sys)  
sys.setdefaultencoding('utf8')

Laat me controleren:

as3:~/ngokevin-site# python
Python 2.7.6 (default, Dec  6 2013, 14:49:02)
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> reload(sys)
<module 'sys' (built-in)>
>>> sys.getdefaultencoding()
'utf8'
>>>

Het bovenstaande laat zien dat de standaardcodering van python utf8 is. Dan is de fout niet meer.


Antwoord 3, autoriteit 21%

Dit is het klassieke “unicode-probleem”. Ik geloof dat het uitleggen hiervan buiten het bestek van een StackOverflow-antwoord valt om volledig uit te leggen wat er gebeurt.

Het wordt hier goed uitgelegd.

Kortom, je hebt iets dat wordt geïnterpreteerd als een reeks bytes doorgegeven aan iets dat het moet decoderen in Unicode-tekens, maar de standaardcodec (ascii) werkt niet.

De presentatie waar ik je op heb gewezen, geeft advies om dit te vermijden. Maak van je code een “unicode sandwich”. In Python 2 helpt het gebruik van from __future__ import unicode_literals.

Update: hoe kan de code worden hersteld:

OK – in je variabele “source” heb je enkele bytes. Het is niet duidelijk uit uw vraag hoe ze daar binnen zijn gekomen – misschien leest u ze van een webformulier? In ieder geval zijn ze niet gecodeerd met ascii, maar Python probeert ze om te zetten naar unicode, ervan uitgaande dat ze dat wel zijn. U moet expliciet vertellen wat de codering is. Dit betekent dat je moet weten wat de codering is! Dat is niet altijd gemakkelijk, en het hangt er helemaal van af waar deze string vandaan komt. Je zou kunnen experimenteren met enkele veelvoorkomende coderingen, bijvoorbeeld UTF-8. Je vertelt unicode() de codering als een tweede parameter:

source = unicode(source, 'utf-8')

Antwoord 4, autoriteit 7%

In sommige gevallen, wanneer u uw standaardcodering controleert (print sys.getdefaultencoding()), geeft het aan dat u ASCII gebruikt. Als u overstapt naar UTF-8, werkt het niet, afhankelijk van de inhoud van uw variabele.
Ik heb een andere manier gevonden:

import sys
reload(sys)  
sys.setdefaultencoding('Cp1252')

Antwoord 5, autoriteit 4%

Ik was aan het zoeken om de volgende foutmelding op te lossen:

unicodedecodeerror: ‘ascii’-codec kan byte 0xe2 op positie 5454 niet decoderen: ordinaal niet binnen bereik (128)

Ik heb het eindelijk opgelost door ‘codering’ op te geven:

f = open('../glove/glove.6B.100d.txt', encoding="utf-8")

Ik wou dat het jou ook kon helpen.


Antwoord 6, autoriteit 3%

"UnicodeDecodeError: 'ascii' codec can't decode byte"

Oorzaak van deze fout: input_string moet unicode zijn, maar str is opgegeven

"TypeError: Decoding Unicode is not supported"

Oorzaak van deze fout: proberen om unicode input_string om te zetten in unicode


Controleer dus eerst of je input_string str is en converteer indien nodig naar unicode:

if isinstance(input_string, str):
   input_string = unicode(input_string, 'utf-8')

Ten tweede verandert het bovenstaande alleen het type, maar worden niet-ascii-tekens niet verwijderd. Als u niet-ascii-tekens wilt verwijderen:

if isinstance(input_string, str):
   input_string = input_string.decode('ascii', 'ignore').encode('ascii') #note: this removes the character and encodes back to string.
elif isinstance(input_string, unicode):
   input_string = input_string.encode('ascii', 'ignore')

Antwoord 7, autoriteit 2%

Om dit op besturingssysteemniveau in een Ubuntu-installatie op te lossen, controleert u het volgende:

$ locale charmap

Als je

. krijgt

locale: Cannot set LC_CTYPE to default locale: No such file or directory

in plaats van

UTF-8

stel vervolgens LC_CTYPE en LC_ALL als volgt in:

$ export LC_ALL="en_US.UTF-8"
$ export LC_CTYPE="en_US.UTF-8"

Antwoord 8

Ik vind dat het het beste is om altijd naar unicode te converteren – maar dit is moeilijk te bereiken, omdat je in de praktijk elk argument zou moeten controleren en converteren naar elke functie en methode die je ooit schrijft die een of andere vorm van stringverwerking bevat.

Dus ik kwam met de volgende aanpak om unicodes of byte-strings te garanderen, van beide invoer. Kortom, neem en gebruik de volgende lambda’s:

# guarantee unicode string
_u = lambda t: t.decode('UTF-8', 'replace') if isinstance(t, str) else t
_uu = lambda *tt: tuple(_u(t) for t in tt) 
# guarantee byte string in UTF8 encoding
_u8 = lambda t: t.encode('UTF-8', 'replace') if isinstance(t, unicode) else t
_uu8 = lambda *tt: tuple(_u8(t) for t in tt)

Voorbeelden:

text='Some string with codes > 127, like Zurich'
utext=u'Some string with codes > 127, like Zurich'
print "==> with _u, _uu"
print _u(text), type(_u(text))
print _u(utext), type(_u(utext))
print _uu(text, utext), type(_uu(text, utext))
print "==> with u8, uu8"
print _u8(text), type(_u8(text))
print _u8(utext), type(_u8(utext))
print _uu8(text, utext), type(_uu8(text, utext))
# with % formatting, always use _u() and _uu()
print "Some unknown input %s" % _u(text)
print "Multiple inputs %s, %s" % _uu(text, text)
# but with string.format be sure to always work with unicode strings
print u"Also works with formats: {}".format(_u(text))
print u"Also works with formats: {},{}".format(*_uu(text, text))
# ... or use _u8 and _uu8, because string.format expects byte strings
print "Also works with formats: {}".format(_u8(text))
print "Also works with formats: {},{}".format(*_uu8(text, text))

Hier is wat meer redeneringen hierover.


Antwoord 9

Kreeg dezelfde fout en dit loste mijn fout op. Bedankt!
python 2 en python 3 die verschillen in unicode-afhandeling, maken gepekelde bestanden behoorlijk incompatibel om te laden. Dus gebruik het coderingsargument van python augurk. De onderstaande link heeft me geholpen om hetzelfde probleem op te lossen toen ik probeerde gepekelde gegevens van mijn python 3.7 te openen, terwijl mijn bestand oorspronkelijk was opgeslagen in de versie van python 2.x.
https://blog. bescheiden-destiny.com/posts/python-2-and-3-compatible-pickle-save-and-load/
Ik kopieer de functie load_pickle in mijn script en riep de load_pickle(pickle_file) aan terwijl ik mijn input_data als volgt laadde:

input_data = load_pickle("my_dataset.pkl")

De load_pickle-functie is hier:

def load_pickle(pickle_file):
    try:
        with open(pickle_file, 'rb') as f:
            pickle_data = pickle.load(f)
    except UnicodeDecodeError as e:
        with open(pickle_file, 'rb') as f:
            pickle_data = pickle.load(f, encoding='latin1')
    except Exception as e:
        print('Unable to load data ', pickle_file, ':', e)
        raise
    return pickle_data

Antwoord 10

Encode converteert een unicode-object naar een string-object. Ik denk dat je een stringobject probeert te coderen. converteer eerst uw resultaat in unicode-object en codeer vervolgens dat unicode-object in ‘utf-8’.
bijvoorbeeld

    result = yourFunction()
    result.decode().encode('utf-8')

Antwoord 11

Dit werkte voor mij:

    file = open('docs/my_messy_doc.pdf', 'rb')

Antwoord 12

Ik had dezelfde fout, met URL’s die niet-ascii-tekens bevatten (bytes met waarden > 128), mijn oplossing:

url = url.decode('utf8').encode('utf-8')

Opmerking: utf-8, utf8 zijn gewoon aliassen . Het gebruik van alleen ‘utf8’ of ‘utf-8’ zou op dezelfde manier moeten werken

In mijn geval, werkte het voor mij, in Python 2.7, ik veronderstel dat deze opdracht ‘iets’ heeft veranderd in de str interne representatie – dat wil zeggen, het dwingt de juiste decodering van de ondersteunde bytereeks in url en plaatst tenslotte de string in een utf-8 str met alle magie op de juiste plaats.
Unicode in Python is zwarte magie voor mij.
Hoop nuttig


Antwoord 13

Ik had hetzelfde probleem, maar het werkte niet voor Python 3. Ik volgde dit en het loste mijn probleem op:

enc = sys.getdefaultencoding()
file = open(menu, "r", encoding = enc)

U moet de codering instellen wanneer u het bestand leest/schrijft.


Antwoord 14

Kortom, om een ​​goede unicode-afhandeling in Python 2 te garanderen:

  • gebruik io.open voor het lezen/schrijven van bestanden
  • gebruik from __future__ import unicode_literals
  • andere gegevensinvoer/uitvoer configureren (bijv. databases, netwerk) om unicode te gebruiken
  • als u geen uitvoer naar utf-8 kunt configureren, converteert u uw uitvoer ervoor print(text.encode('ascii', 'replace').decode())

Zie voor uitleg het gedetailleerde antwoord van @Alastair McCormack.


Antwoord 15

Ik heb hetzelfde probleem met de string “PastelerA a Mallorca” en heb ik opgelost met:

unicode("PastelerA­a Mallorca", 'latin-1')

Antwoord 16

In een Django (1.9.10)/Python 2.7.5-project heb ik frequente UnicodeDecodeError-uitzonderingen; vooral wanneer ik unicode-reeksen probeer te loggen. Ik heb een hulpfunctie gemaakt voor willekeurige objecten om in principe te formatteren naar 8-bits ascii-strings en alle tekens die niet in de tabel staan ​​te vervangen door ‘?’. Ik denk dat het niet de beste oplossing is, maar aangezien de standaardcodering ascii is (en ik wil het niet veranderen), is het voldoende:

def encode_for_logging(c, encoding='ascii'):
  if isinstance(c, basestring):
    return c.encode(codering, 'vervangen')
  elif isinstance(c, Iterable):
    c_ = []
    voor v in c:
      c_.append(encode_for_logging(v, codering))
    retour c_
  anders:
    return encode_for_logging(unicode(c))

`


Antwoord 17

Deze fout treedt op wanneer er enkele niet-ASCII-tekens in onze tekenreeks staan ​​en we bewerkingen op die tekenreeks uitvoeren zonder de juiste decodering.
Dit heeft me geholpen om mijn probleem op te lossen.
Ik lees een CSV-bestand met kolommen ID, Tekst en decodeertekens erin, zoals hieronder:

train_df = pd.read_csv("Example.csv")
train_data = train_df.values
for i in train_data:
    print("ID :" + i[0])
    text = i[1].decode("utf-8",errors="ignore").strip().lower()
    print("Text: " + text)

Antwoord 18

Specificeer: # encoding= utf-8 bovenaan uw Python-bestand, het zou het probleem moeten oplossen


Antwoord 19

Ik heb deze fout ervaren met Python2.7. Het overkwam me terwijl ik veel python-programma’s probeerde uit te voeren, maar ik slaagde erin om het te reproduceren met dit eenvoudige script:

#!/usr/bin/env python
import subprocess
import sys
result = subprocess.Popen([u'svn', u'info'])
if not callable(getattr(result, "__enter__", None)) and not callable(getattr(result, "__exit__", None)):
    print("foo")
print("bar")

Bij succes zou het ‘foo’ en ‘bar’ moeten afdrukken, en waarschijnlijk een foutmelding als u zich niet in een svn-map bevindt.

Als het niet lukt, moet het ‘UnicodeDecodeError: ‘ascii’ codec kan byte 0xc4 op positie 39: ordinaal niet binnen bereik (128)’ niet decoderen afdrukken.

Na het opnieuw genereren van mijn landinstellingen en vele andere oplossingen die in deze vraag zijn gepost, kwam ik erachter dat de fout optrad omdat ik een speciaal teken (l) had gecodeerd in mijn PATH-omgevingsvariabele. Nadat ik het PATH in ‘~/.bashrc’ had hersteld, mijn sessie had afgesloten en opnieuw had ingevoerd (blijkbaar werkte het zoeken naar ‘~/.bashrc’ niet), probleem was verdwenen.

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Other episodes