web-dev-qa-db-de.com

UnicodeEncodeError: Der Codec 'ascii' kann das Zeichen u '\ xa0' an Position 20 nicht codieren: Ordnungszahl nicht im Bereich (128)

Ich habe Probleme mit Unicode-Zeichen aus Text, der von verschiedenen Webseiten (auf verschiedenen Websites) abgerufen wurde. Ich benutze BeautifulSoup.

Das Problem ist, dass der Fehler nicht immer reproduzierbar ist. Manchmal funktioniert es mit einigen Seiten und manchmal wird es durch das Werfen eines UnicodeEncodeError unterbrochen. Ich habe so gut wie alles ausprobiert, was mir einfällt, und dennoch habe ich nichts gefunden, was durchgehend funktioniert, ohne eine Art Unicode-Fehler zu verursachen.

Einer der Codeabschnitte, die Probleme verursachen, ist unten aufgeführt:

agent_telno = agent.find('div', 'agent_contact_number')
agent_telno = '' if agent_telno is None else agent_telno.contents[0]
p.agent_info = str(agent_contact + ' ' + agent_telno).strip()

Hier ist eine Stapelablaufverfolgung, die auf einigen Zeichenfolgen erstellt wird, wenn das obige Snippet ausgeführt wird:

Traceback (most recent call last):
  File "foobar.py", line 792, in <module>
    p.agent_info = str(agent_contact + ' ' + agent_telno).strip()
UnicodeEncodeError: 'ascii' codec can't encode character u'\xa0' in position 20: ordinal not in range(128)

Ich vermute, dass dies daran liegt, dass einige Seiten (oder insbesondere Seiten von einigen Websites) möglicherweise codiert sind, während andere möglicherweise nicht codiert sind. Alle Websites haben ihren Sitz in Großbritannien und liefern Daten, die für den Verbrauch in Großbritannien bestimmt sind. Es gibt also keine Probleme im Zusammenhang mit der Internalisierung oder dem Umgang mit Texten, die in einer anderen Sprache als Englisch verfasst wurden.

Hat jemand eine Idee, wie man das löst, damit ich das Problem KONSISTENT beheben kann?

1183

Sie müssen das Python nicode-HOWTO lesen. Dieser Fehler ist das allererste Beispiel .

Stoppen Sie grundsätzlich die Verwendung von str, um von Unicode in codierten Text/Byte zu konvertieren.

Verwenden Sie stattdessen richtig .encode() , um die Zeichenfolge zu codieren:

p.agent_info = u' '.join((agent_contact, agent_telno)).encode('utf-8').strip()

oder arbeiten ganz in Unicode.

1266
agf

Dies ist ein klassischer python Unicode-Schmerzpunkt! Folgendes berücksichtigen:

a = u'bats\u00E0'
print a
 => batsà

Bis jetzt ist alles in Ordnung, aber wenn wir str (a) aufrufen, wollen wir sehen, was passiert:

str(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe0' in position 4: ordinal not in range(128)

Oh Dip, das wird niemandem nützen! Um den Fehler zu beheben, codieren Sie die Bytes explizit mit .encode und teilen Sie python mit, welcher Codec verwendet werden soll:

a.encode('utf-8')
 => 'bats\xc3\xa0'
print a.encode('utf-8')
 => batsà

Voil\u00E0!

Das Problem ist, dass python beim Aufrufen von str () die Standardzeichencodierung verwendet, um die angegebenen Bytes zu codieren. In Ihrem Fall handelt es sich hierbei manchmal um Darstellungen von Unicode-Zeichen. Um das Problem zu beheben, müssen Sie python mithilfe von .encode ('whatever_unicode') mitteilen, wie mit dem angegebenen String umgegangen werden soll. Die meiste Zeit sollten Sie mit utf-8 zurechtkommen.

Eine hervorragende Darstellung zu diesem Thema finden Sie in Ned Batchelders PyCon-Vortrag hier: http://nedbatchelder.com/text/unipain.html

417
Andbdrew

Ich fand eine elegante Möglichkeit, Symbole zu entfernen und die Zeichenfolge wie folgt beizubehalten:

yourstring = yourstring.encode('ascii', 'ignore').decode('ascii')

Es ist wichtig zu beachten, dass die Verwendung der Ignorier-Option gefährlich ist, da durch die Verwendung der Ignorier-Option im Hintergrund jegliche Unicode- (und Internationalisierungs-) Unterstützung aus dem Code entfernt wird, der sie verwendet.

>>> u'City: Malmö'.encode('ascii', 'ignore').decode('ascii')
'City: Malm'
196
Max Korolevsky

nun, ich habe alles versucht, aber es hat nicht geholfen, nachdem ich herumgegoogelt habe, habe ich Folgendes herausgefunden und es hat geholfen. python 2.7 wird verwendet.

# encoding=utf8
import sys
reload(sys)
sys.setdefaultencoding('utf8')
140
Ashwin

Ein subtiles Problem, das dazu führt, dass selbst das Drucken fehlschlägt, besteht darin, dass Ihre Umgebungsvariablen falsch eingestellt sind, z. hier wird LC_ALL auf "C" gesetzt. In Debian raten sie davon ab, dies einzustellen: Debian-Wiki auf Gebietsschema

$ echo $LANG
en_US.utf8
$ echo $LC_ALL 
C
$ python -c "print (u'voil\u00e0')"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe0' in position 4: ordinal not in range(128)
$ export LC_ALL='en_US.utf8'
$ python -c "print (u'voil\u00e0')"
voilà
$ unset LC_ALL
$ python -c "print (u'voil\u00e0')"
voilà
80
maxpolk

Für mich war das Folgende:

BeautifulSoup(html_text,from_encoding="utf-8")

Hoffe das hilft jemandem.

27
Animesh

Ich habe tatsächlich festgestellt, dass es in den meisten Fällen viel einfacher ist, diese Zeichen nur herauszunehmen:

s = mystring.decode('ascii', 'ignore')
24
Phil LaNasa

Versuchen Sie, dies zu lösen,

# encoding=utf8
import sys
reload(sys)
sys.setdefaultencoding('utf8')
20
Joseph Daudi

Das Problem ist, dass Sie versuchen, ein Unicode-Zeichen zu drucken, dieses jedoch von Ihrem Terminal nicht unterstützt wird.

Sie können versuchen, das Paket _language-pack-en_ zu installieren, um Folgendes zu beheben:

_Sudo apt-get install language-pack-en
_

hier werden Aktualisierungen der englischen Übersetzungsdaten für alle unterstützten Pakete (einschließlich Python) bereitgestellt. Installieren Sie bei Bedarf ein anderes Sprachpaket (je nachdem, welche Zeichen Sie drucken möchten).

Bei einigen Linux-Distributionen ist es erforderlich, um sicherzustellen, dass die standardmäßigen englischen Ländereinstellungen ordnungsgemäß eingerichtet sind (damit Unicode-Zeichen von Shell/Terminal verarbeitet werden können). Manchmal ist es einfacher zu installieren, als es manuell zu konfigurieren.

Stellen Sie dann beim Schreiben des Codes sicher, dass Sie die richtige Codierung in Ihrem Code verwenden.

Zum Beispiel:

_open(foo, encoding='utf-8')
_

Wenn Sie immer noch ein Problem haben, überprüfen Sie Ihre Systemkonfiguration wie folgt:

  • Ihre Gebietsschemadatei (_/etc/default/locale_), die z.

    _LANG="en_US.UTF-8"
    LC_ALL="en_US.UTF-8"
    _

    oder:

    _LC_ALL=C.UTF-8
    LANG=C.UTF-8
    _
  • Wert von LANG/ LC_CTYPE in Shell.

  • Überprüfen Sie, welches Gebietsschema Ihre Shell unterstützt:

    _locale -a | grep "UTF-8"
    _

Demonstration des Problems und der Lösung in einer neuen VM.

  1. Initialisieren und stellen Sie das VM bereit (z. B. mit vagrant ):

    _vagrant init ubuntu/trusty64; vagrant up; vagrant ssh
    _

    Siehe: verfügbare Ubuntu-Boxen ..

  2. Drucken von Unicode-Zeichen (z. B. Markenzeichen wie __):

    _$ python -c 'print(u"\u2122");'
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
    UnicodeEncodeError: 'ascii' codec can't encode character u'\u2122' in position 0: ordinal not in range(128)
    _
  3. Installieren Sie jetzt _language-pack-en_:

    _$ Sudo apt-get -y install language-pack-en
    The following extra packages will be installed:
      language-pack-en-base
    Generating locales...
      en_GB.UTF-8... /usr/sbin/locale-gen: done
    Generation complete.
    _
  4. Nun sollte das Problem gelöst sein:

    _$ python -c 'print(u"\u2122");'
    ™
    _
  5. Versuchen Sie andernfalls den folgenden Befehl:

    _$ LC_ALL=C.UTF-8 python -c 'print(u"\u2122");'
    ™
    _
19
kenorb

Fügen Sie die folgende Zeile am Anfang Ihres Skripts ein (oder als zweite Zeile):

# -*- coding: utf-8 -*-

Das ist die Definition von python Quellcode-Codierung. Weitere Informationen in PEP 26 .

16
Andriy Ivaneyko

Hier ist eine Wiederholung einiger anderer sogenannter "cop out" Antworten. Es gibt Situationen, in denen es trotz der hier geäußerten Proteste eine gute Lösung ist, die lästigen Zeichen/Zeichenketten einfach wegzuwerfen.

def safeStr(obj):
    try: return str(obj)
    except UnicodeEncodeError:
        return obj.encode('ascii', 'ignore').decode('ascii')
    except: return ""

Testen Sie es:

if __== '__main__': 
    print safeStr( 1 ) 
    print safeStr( "test" ) 
    print u'98\xb0'
    print safeStr( u'98\xb0' )

Ergebnisse:

1
test
98°
98

Vorschlag: Vielleicht möchten Sie diese Funktion stattdessen toAscii nennen? Das ist eine Frage der Präferenz.

Dies wurde für Python 2 geschrieben. Für Python 3 möchten Sie meines Erachtens bytes(obj,"ascii") anstelle von str(obj) verwenden. . Ich habe das noch nicht getestet, aber ich werde die Antwort irgendwann überarbeiten.

14
BuvinJ

In Shell:

  1. Suchen Sie das unterstützte UTF-8-Gebietsschema mit dem folgenden Befehl:

    locale -a | grep "UTF-8"
    
  2. Exportieren Sie es, bevor Sie das Skript ausführen, z.

    export LC_ALL=$(locale -a | grep UTF-8)
    

    oder manuell wie:

    export LC_ALL=C.UTF-8
    
  3. Testen Sie es, indem Sie ein Sonderzeichen drucken, z. :

    python -c 'print(u"\u2122");'
    

Oben in Ubuntu getestet.

11
kenorb

Ich füge den folgenden Code immer in die ersten beiden Zeilen der python -Dateien ein:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals
8
Pereira

Einfache Hilfsfunktionen gefunden hier .

def safe_unicode(obj, *args):
    """ return the unicode representation of obj """
    try:
        return unicode(obj, *args)
    except UnicodeDecodeError:
        # obj is byte string
        ascii_text = str(obj).encode('string_escape')
        return unicode(ascii_text)

def safe_str(obj):
    """ return the byte string representation of obj """
    try:
        return str(obj)
    except UnicodeEncodeError:
        # obj is unicode
        return unicode(obj).encode('unicode_escape')

Füge einfach einen variablen Code hinzu ('utf-8')

agent_contact.encode('utf-8')
5

Dies hilft in python 2.7

import sys
reload(sys)   
sys.setdefaultencoding('utf-8')

Dies hilft, sys.setdefaultencoding () wieder zu aktivieren.

5
Edward Okech

Die folgende Lösung hat bei mir funktioniert

u "String"

(repräsentiert den String als Unicode) vor meinem String.

result_html = result.to_html(col_space=1, index=False, justify={'right'})

text = u"""
<html>
<body>
<p>
Hello all, <br>
<br>
Here's weekly summary report.  Let me know if you have any questions. <br>
<br>
Data Summary <br>
<br>
<br>
{0}
</p>
<p>Thanks,</p>
<p>Data Team</p>
</body></html>
""".format(result_html)

Bitte öffnen Sie das Terminal und geben Sie den folgenden Befehl ein:

export LC_ALL="en_US.UTF-8"

Ich habe gerade folgendes benutzt:

import unicodedata
message = unicodedata.normalize("NFKD", message)

Überprüfen Sie, was die Dokumentation dazu sagt:

unicodedata.normalize (form, unistr) Gibt das normale Formular für die Unicode-Zeichenfolge unistr zurück. Gültige Werte für das Formular sind "NFC", "NFKC", "NFD" und "NFKD".

Der Unicode-Standard definiert verschiedene Normalisierungsformen einer Unicode-Zeichenfolge auf der Grundlage der Definition der kanonischen Äquivalenz und der Kompatibilitätsäquivalenz. In Unicode können mehrere Zeichen auf unterschiedliche Weise ausgedrückt werden. Beispielsweise kann das Zeichen U + 00C7 (lateinischer Großbuchstabe C mit Cedille) auch als die Sequenz U + 0043 (lateinischer Großbuchstabe C) U + 0327 (kombinierende Cedille) ausgedrückt werden.

Für jedes Zeichen gibt es zwei Normalformen: Normalform C und Normalform D. Normalform D (NFD) wird auch als kanonische Zerlegung bezeichnet und übersetzt jedes Zeichen in seine zerlegte Form. Die normale Form C (NFC) wendet zuerst eine kanonische Zerlegung an und setzt dann wieder vorkombinierte Zeichen zusammen.

Zusätzlich zu diesen beiden Formen gibt es zwei weitere Normalformen, die auf der Kompatibilitätsäquivalenz basieren. In Unicode werden bestimmte Zeichen unterstützt, die normalerweise mit anderen Zeichen vereinheitlicht werden. Zum Beispiel ist U + 2160 (ROMAN NUMERAL ONE) wirklich dasselbe wie U + 0049 (LATIN CAPITAL LETTER I). Es wird jedoch in Unicode aus Gründen der Kompatibilität mit vorhandenen Zeichensätzen (z. B. gb2312) unterstützt.

Die normale Form KD (NFKD) wendet die Kompatibilitätszerlegung an, d. H. Ersetzt alle Kompatibilitätszeichen durch ihre Äquivalente. Die normale Form KC (NFKC) wendet zuerst die Kompatibilitätszerlegung an, gefolgt von der kanonischen Zusammensetzung.

Auch wenn zwei Unicode-Zeichenfolgen normalisiert sind und für einen menschlichen Leser gleich aussehen, werden sie möglicherweise nicht gleich verglichen, wenn eine Zeichen kombiniert und die andere nicht.

Löst es für mich. Simpel und einfach.

3
Drag0

Dieser Fehler ist aufgetreten, als manage.py migrate in Django mit lokalisierten Fixtures ausgeführt wurde.

Unsere Quelle enthielt die # -*- coding: utf-8 -*- -Deklaration, MySQL war korrekt für utf8 konfiguriert und Ubuntu hatte das entsprechende Sprachpaket und die entsprechenden Werte in /etc/default/locale.

Das Problem war einfach, dass dem Container Django (wir verwenden Docker) die Umgebungsvariable LANG fehlte.

Das Problem wurde behoben, indem LANG auf en_US.UTF-8 gesetzt und der Container neu gestartet wurde, bevor Migrationen erneut ausgeführt wurden.

2
followben

Leider funktioniert dies in Python 3 zumindest ...

Python

Manchmal liegt der Fehler in den Umgebungsvariablen und damit im Zusammenhang

import os
import locale
os.environ["PYTHONIOENCODING"] = "utf-8"
myLocale=locale.setlocale(category=locale.LC_ALL, locale="en_GB.UTF-8")
... 
print(myText.encode('utf-8', errors='ignore'))

wobei Fehler bei der Codierung ignoriert werden.

1
hhh

Ich hatte gerade dieses Problem, und Google hat mich hierher geführt. Nur um die allgemeinen Lösungen hierher zu ergänzen:

# 'value' contains the problematic data
unic = u''
unic += value
value = unic

Ich hatte diese Idee, nachdem ich Neds Präsentation gelesen hatte.

Ich behaupte jedoch nicht vollständig zu verstehen, warum dies funktioniert. Wenn also jemand diese Antwort bearbeiten oder einen Kommentar zur Erklärung eingeben kann, bin ich dankbar dafür.

1
pepoluan

Viele Antworten hier (zum Beispiel @agf und @Andbdrew) haben bereits die unmittelbarsten Aspekte der OP-Frage angesprochen.

Ich denke jedoch, dass es einen subtilen, aber wichtigen Aspekt gibt, der weitgehend ignoriert wurde und der für alle, die mich mögen, von großer Bedeutung ist, als sie versuchten, die Kodierungen in Python zu verstehen: Python 2 vs Python 3 Die Verwaltung der Zeichendarstellung ist völlig anders . Ich fühle mich verwirrt, wenn Leute über Kodierungen in Python lesen, ohne sich der Version bewusst zu sein.

Ich schlage vor, dass jeder, der die Grundursache des OP-Problems verstehen möchte, zunächst Spolskys Einführung in Zeichendarstellungen und Unicode liest und dann Batchelder unter Unicode in Python wechselt. 2 und Python 3.

Vermeiden Sie die Konvertierung von Variablen in str (Variable). Manchmal kann es das Problem verursachen.

Ein einfacher Tipp, um Folgendes zu vermeiden:

try: 
    data=str(data)
except:
    data = str(data)

Das obige Beispiel löst auch Encode erro.

0
sam ruben

Wenn Sie etwas wie packet_data = "This is data" haben, dann tun Sie dies in der nächsten Zeile direkt nach der Initialisierung von packet_data:

unic = u''
packet_data = unic
0
Nandan Kulkarni

Update für python 3.0 und höher. Versuchen Sie Folgendes im python Editor:

locale-gen en_US.UTF-8
export LANG=en_US.UTF-8 LANGUAGE=en_US.en
LC_ALL=en_US.UTF-8

Dadurch wird die Standardcodierung für das Gebietsschema des Systems auf das UTF-8-Format festgelegt.

Weitere Informationen finden Sie unter hier bei PEP 538 - Erzwingen der Umwandlung des alten Gebietsschemas C in ein UTF-8-basiertes Gebietsschema .

0
ZF007

Ich hatte dieses Problem beim Versuch, Unicode-Zeichen in stdout auszugeben, aber mit sys.stdout.write, anstatt sie zu drucken (damit ich die Ausgabe auch in eine andere Datei unterstützen kann).

Aus der Dokumentation von BeautifulSoup habe ich das mit der Codec-Bibliothek gelöst:

import sys
import codecs

def main(fIn, fOut):
    soup = BeautifulSoup(fIn)
    # Do processing, with data including non-ASCII characters
    fOut.write(unicode(soup))

if __== '__main__':
    with (sys.stdin) as fIn: # Don't think we need codecs.getreader here
        with codecs.getwriter('utf-8')(sys.stdout) as fOut:
            main(fIn, fOut)
0
palswim