UnicodeDecodeError: 'ascii'

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
torres
User
Beiträge: 47
Registriert: Samstag 29. Januar 2011, 13:23

Hallo,

habe aktuell folgendes Problem:
Ich lese ein Textfile ein und bekomme:
File "/usr/local/lib/python3.1/encodings/ascii.py", line 26, in decode
return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xf6 in position 15: ordinal not in range(128)

Jetzt habe ich das hier gelesen:
http://www.python-forum.de/viewtopic.php?f=1&t=17437
und ein line=iso88591.decode(line) eingefuegt:

Code: Alles auswählen

    #dateistr=""
    dateistr=iso88591.decode("")
    for line in objects_f:
        line=iso88591.decode(line)
        if not line.startswith('#'):
            dateistr += line
und dann bekomme ich:
NameError: global name 'iso88591' is not defined

dann hab ich oben noch:
# -*- coding: iso-8859-1 -*- eingefuegt
und hab noch immer den Fehler (und frage mcih auch was die Zeile soll= (denn meine.py ist ja ascii))

oder so:

Code: Alles auswählen

    dateistr="" 
    # Text definieren
    # s_iso88591 = "Hallo .."
    # Text nach Unicode umwandeln
    # s_unicode = s_iso88591.decode("iso-8859-1")
    dateistr = dateistr.decode("iso-8859-1")
Fehler: AttributeError: 'str' object has no attribute 'decode'

und kenne mich nun gar nicht mehr aus :-(

Dann hab ich mal den ganzen Code aus dem Posting (http://www.python-forum.de/viewtopic.php?f=1&t=17437) getestet:

Code: Alles auswählen

python3.1    
Python 3.1.2 (r312:79147, Feb 11 2011, 21:32:43) 
[GCC 4.2.1 20070719  [FreeBSD]] on freebsd8
Type "help", "copyright", "credits" or "license" for more information.
>>> # -*- coding: iso-8859-1 -*-
...  
... # Text definieren
... s_iso88591 = "Hallo \xd6sterreich"
>>>  
... # Text nach Unicode umwandeln
... s_unicode = s_iso88591.decode("iso-8859-1")
Traceback (most recent call last):
  File "<stdin>", line 3, in <module>
AttributeError: 'str' object has no attribute 'decode'
>>>  
... # Text nach UTF-8 umwandeln
... s_utf8 = s_unicode.encode("utf-8")
Traceback (most recent call last):
  File "<stdin>", line 3, in <module>
NameError: name 's_unicode' is not defined
ich brauch jetzt echt bitte Hilfe (ich kann ja nichts fdafuer, dass es in meinem File ein "ue" gibt (weiss selber nicht, wie man das ueberhaupt tippen kann)
:oops:

Gruss Torres
Benutzeravatar
sparrow
User
Beiträge: 4164
Registriert: Freitag 17. April 2009, 10:28

1. Wo kommt die Datei her?

2. Welche Zeiche stehen drin?

3. Welches Betriebssystem nutzt du?

4. Wie sieht dein Code aus der den Fehler wirft?


Edit: Ok, ich sehe die Infos sind schon fast alle im ersten Beitrag.
Außer: wo kommt die Datei her?
torres
User
Beiträge: 47
Registriert: Samstag 29. Januar 2011, 13:23

Hallo sparrow,
sparrow hat geschrieben:1. Wo kommt die Datei her?
es ist eine 2.5M nagios objects.cache Datei, die auf einem Linux System geschrieben wurde
sparrow hat geschrieben: 2. Welche Zeiche stehen drin?
Nun ja, da koennte theoretisch alles das drin sein: a-z,A-z,0-9,und:
!"§$%&/\()[]#'~*+-:;|<> und eben evtl Umlaute und ss
Ich habe noch eine andere Datei, bei der geht es ganz normal, soweit ich das ueberpruefen kann.
gibt es in der keine Umlaute. Mit Python 2.6.5 funktionieren beide Dateien.
sparrow hat geschrieben: 3. Welches Betriebssystem nutzt du?
Freebsd hier
sparrow hat geschrieben: 4. Wie sieht dein Code aus der den Fehler wirft?

Code: Alles auswählen

#!/usr/bin/env python3.1
import pprint,re,string

objects_f = open(PPATH+"file", "r")
def read_objects_f():
    dateistr=""
    for line in objects_f:
        if not line.startswith('#'):
            dateistr += line
    objects_f.close()
(..)
defelementdict=read_objects_f()

Viele Gruesse,
Torres
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Vergiss den andern Thread, der bezieht sich auf Python 2.
Das Encoding-Cookie sollte dem Encoding entsprechen, in dem die Datei auch tatsaechlich ist, da es auch nur fuer die Sourcedatei gilt und _nicht_ fuer I/O.

Zeig den Code den du tatsaechlich verwendest und den 1. Fehler produziert, der Rest kommt vor allem daher zustande, dass du den Unterschiede zwischen Python 2 und 3 nicht kennst und das einfach uebernimmst.

Edit: Da der Code jetzt da ist: Das ist ja graesslich. Verwende mal codecs.open statt `open`.
Benutzeravatar
sparrow
User
Beiträge: 4164
Registriert: Freitag 17. April 2009, 10:28

Oh, das ist Python 3.

Da gibt es nur noch 2 Typen für "Zeichenketten", str (was immer encodiert ist) und bytes.

mit str.encode('zeichensatz') macht man aus dem string bytes, mit bytes.decode('zeichensatz') macht man aus den bytes einen encodiertenstring.
Die Anleitung die du gelesen hast scheint für Python 2 zu sein.

Das ist aber für dich irrelevant, denn Python gibt dir die Möglichkeit an die Hand eine geöffnete Datei direkt mit einem bestimmten Encoding zu öffnen:

Code: Alles auswählen

objects_f = open(PPATH+"file", "r", encoding='utf-8')
würde eine Datei die utf-8 codiert ist entsprechend öffnen. Das sollte eigentlich bei Linux-Dateien der Fall sein. Zumindest kenne ich keine aktuelle Distribution die andere Zeichensätze verwendet.
Ich wundere mich nur, dass FreeBSD damit nicht arbeitet?

Was sagt wohl

Code: Alles auswählen

import sys
sys.getdefaultencoding()
?
torres
User
Beiträge: 47
Registriert: Samstag 29. Januar 2011, 13:23

cofi hat geschrieben:Das ist ja graesslich. Verwende mal codecs.open statt `open`.
objects_f = codecs.open(PPATH+"file", "r", 'iso-8859-1')

Jetzt geht es!

VIELEN DANK!
Gruss,
Torres
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

sparrow hat geschrieben:Oh, das ist Python 3.

Da gibt es nur noch 2 Typen für "Zeichenketten", str (was immer encodiert ist) und bytes.

mit str.encode('zeichensatz') macht man aus dem string bytes, mit bytes.decode('zeichensatz') macht man aus den bytes einen encodiertenstring.
Also das stimmt so ja grad nicht, bzw. wirft einiges durcheinander!

Strings sind in Python 3 immer Unicode. Du hast das ja letztlich schon durch de Hinweis auf en- bzw.decode angedeutet. Nur stimmt Deine Nomenklatur hier nicht. decode() macht eben keinen encodierten String aus etwas - da wäre der Name decode() ja quasi eine Verarschung ;-)

@torres: Es gibt hier Python-Code-Tags für das Posten von Quellcode. Bitte benutze die doch, auch für kurze Snippets. Pfade solltest Du nie mit "+" o.ä. konkatenieren, es gibt da spezielle Funktionen. In Python 2.x ist es os.path.join(), evtl. liegt die Funktion in Python 3 in einem anderen Modul. Aber sie wird es geben ;-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
torres
User
Beiträge: 47
Registriert: Samstag 29. Januar 2011, 13:23

Hallo,

hab jetzt os.path.join(a, *p) verwendet. Das kuemmert sich um die '/' , recht nett,
falls man es mal vergisst. Danke fuer den Tip!

Allerdings habe ich jetzt wiederum ein encoding Problem, wenn ich aus dem eingelesenen
Dictionary etwas printen moechte. Wenn Du oben schreibst, dass Strings generell utf-8 sind,
dann muss ich jetzt bei jeder Methode, die einen String erwartet vorher encodieren. oder?
(etwas laesstig stelle ich es mir schon vor)
Habe dazu das in meinem "Python 3" Buch(*) gefunden:

Code: Alles auswählen

print(e['alias'].encode('iso-8859-1'))
Gibt es da etwas schoeneres?, weil ich moechte doch die Datei parsen und nun muss ich
ueberall das encode() mit dranschreiben, das wird doch schrecklich unuebersichtlich. Koennte man den Defaultwert nicht umsetzen? Irgendwie? Irgendwo?

edit:
und der Print Output schaut so aus: b'BAIS-\xdcberwachungszeit' - und das gefaellt mir ja auch nicht, denn es sollte sein: BAIS-\xdcberwachungszeit. Muss ich das jetzt ueberall noch wegsubstituieren?

Viele Gruesse,
Torres


(* (M. Weigend) Aber die Loesung von gestern fand ich darin nicht. Und es gibt einen Tippfehler auf S. 349, dort steht "iso-88559-1", das ist LookupError: unknown encoding: iso-88559-1)
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

torres hat geschrieben: Wenn Du oben schreibst, dass Strings generell utf-8 sind,
dann muss ich jetzt bei jeder Methode, die einen String erwartet vorher encodieren. oder?
Wer hat das wo geschrieben? Das kann niemals stimmen! ;-)

Zum Einrahmen:
utf-8 != Unicode!!!

Das ist extrem wichtig zu kapieren - das musste ich auch schmerzhaft lernen!

Lies mal die Links in meiner Signatur durch, danach solltest Du klarer sehen.

In Python 3 sind alle Strings Unicode. Per default geht der Interpreter davon aus, dass er bei automatischen Wandlungen Unicode in utf-8 codierte Bytes umsetzt. Das wäre z.B. bei print() der Fall. Ich nehme mal stark an, dass man da ein Encoding angeben kann.

Vermutlich kann man in Python3 ebenfalls ein Default-Encoding Cookie angeben - dieses Encoding dürfte dann sicher auch von print() benutzt werden.

Interessant diesbezüglich ist auch diese Übersicht:
http://docs.python.org/py3k/whatsnew/3. ... e-vs-8-bit

Bei diesem Thema muss man also zudem höllisch aufpassen, ob man von Python2 oder 3 redet.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

@torres: Strings sind in Python 3 grundsätzlich Unicode und nicht UTF-8. Das ist nicht das selbe. UTF-8 wäre ja schon wieder eine Kodierung -- in der zum Beispiel Byteketten vorliegen können. Ich glaube Du hast die Zusammenhänge da immer noch nicht so ganz durchdrungen.

Wobei ich `print()` bei Python 3 in dem Zusammenhang als problem und im Grunde ziemlich unbrauchbar ansehe. Damit kann man im Grunde nichts ausserhalb von ASCII ausgeben ohne Gefahr zu laufen auf die Schnauze zu fallen. Vergiss das am besten.
Benutzeravatar
/me
User
Beiträge: 3554
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

torres hat geschrieben:Allerdings habe ich jetzt wiederum ein encoding Problem, wenn ich aus dem eingelesenen
Dictionary etwas printen moechte. Wenn Du oben schreibst, dass Strings generell utf-8 sind,
dann muss ich jetzt bei jeder Methode, die einen String erwartet vorher encodieren. oder?
In Python 3 sind Strings generell Unicode. Sie müssen nur dann in ein Encoding (UTF8, ISO-8859-15, ...) überführt werden wenn das von der aufgerufenen Methode erwartet wird.
torres
User
Beiträge: 47
Registriert: Samstag 29. Januar 2011, 13:23

Hallo,

schade, leider gibt es kein setdefaultencoding, nur ein getdefaultencoding:

Code: Alles auswählen

pydoc3-3.1 sys
    getdefaultencoding(...)
        getdefaultencoding() -> string
    
        Return the current default string encoding used by the Unicode
        implementation.
und print hat auch nichts parat:

Code: Alles auswählen

print(...)
    print(value, ..., sep=' ', end='\n', file=sys.stdout)
 
    Prints the values to a stream, or to sys.stdout by default.
    Optional keyword arguments:
    file: a file-like object (stream); defaults to the current sys.stdout.
    sep:  string inserted between values, default a space.
    end:  string appended after the last value, default a newline.
torres
User
Beiträge: 47
Registriert: Samstag 29. Januar 2011, 13:23

Hallo,

also jetzt bin ich schon so weit:

einmal das hier gelesen:
http://bytes.com/topic/python/answers/8 ... world-ever

Darum sollte ich eigentlich die locale setzen, um hernach
bei

Code: Alles auswählen

>>> sys.stdout.encoding
'US-ASCII'
etwas wie de_DE.ISO8859-1 zu sehen:

Code: Alles auswählen

import locale
>>> locale.setlocale(locale.LC_CTYPE,"de_DE.ISO8859-1")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.1/locale.py", line 535, in setlocale
    return _setlocale(category, locale)
locale.Error: unsupported locale setting

>>> locale.setlocale(locale.LC_ALL,"de_DE.ISO8859-1")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.1/locale.py", line 535, in setlocale
    return _setlocale(category, locale)
locale.Error: unsupported locale setting
dann habe ich /usr/lib/python3.1/locale.py durchgelesen:

Code: Alles auswählen

(..)
locale_encoding_alias = {

    # Mappings for non-standard encoding names used in locale names
    '437':                          'C',
    'c':                            'C',
    'en':                           'ISO8859-1',
    'jis':                          'JIS7',
    'jis7':                         'JIS7',
    'ajec':                         'eucJP',

    # Mappings from Python codec names to C lib encoding names
    'ascii':                        'ISO8859-1',
    'latin_1':                      'ISO8859-1',
    'iso8859_1':                    'ISO8859-1',
(..)
aber, das tut alles nicht:

Code: Alles auswählen

>>> locale.setlocale(locale.LC_CTYPE,'ISO8859-1')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.1/locale.py", line 535, in setlocale
    return _setlocale(category, locale)
locale.Error: unsupported locale setting
>>> locale.setlocale(locale.LC_ALL,'ISO8859-1')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.1/locale.py", line 535, in setlocale
    return _setlocale(category, locale)
locale.Error: unsupported locale setting

kurz und ungut: ich kann dahintippen was ich will :-/

das geht:

Code: Alles auswählen

locale.setlocale(locale.LC_ALL,'en_US.UTF-8')
'en_US.UTF-8'

Code: Alles auswählen

man locale:
-a, --all-locales
               Write names of available locales.


locale -a
C
en_AG
en_AG.utf8
en_AU.utf8
en_BW.utf8
en_CA.utf8
en_DK.utf8
en_GB.utf8
en_HK.utf8
en_IE.utf8
en_IN
en_IN.utf8
en_NG
en_NG.utf8
en_NZ.utf8
en_PH.utf8
en_SG.utf8
en_US.utf8
en_ZA.utf8
en_ZW.utf8
POSIX
zh_CN.utf8
zh_SG.utf8
entsprechend geht auch:

Code: Alles auswählen

locale.setlocale(locale.LC_ALL,'en_ZA.utf8')
'en_ZA.utf8'
tja, muss ich da welche installieren?! Und was wuerde jemanden in Moskau bluehen, der mein python Script ausfuehrt und keine entsprechenden "locales" installiert hat?
Warum war das bei python 2.x kein Problem? Sollte ich vielleicht wieder auf python 2.x umsteigen?


Gruss,
Torres
torres
User
Beiträge: 47
Registriert: Samstag 29. Januar 2011, 13:23

Fuer python 2.6 gibt es da was, fuer 3.1 nicht
/usr/local/lib/python2.6/encodings/iso8859_1.py

Viele Gruesse
Torres, voll frustriert und sich fragend: wie macht IHR denn das?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

torres hat geschrieben:Viele Gruesse
Torres, voll frustriert und sich fragend: wie macht IHR denn das?
Naja, mich hat BlackJacks Aussage bezüglich der print-Funktion von Python 3.x auch irritiert. Hätte gewettet, dass es da einen encoding-Parameter o.ä. gibt.

Allerdings ist es für Programme ja nicht wirklich entscheidend, ob man per print alles mögliche absetzen kann. Im Regelfall hat man ja eine GUI, eine DB, eine Textdatei o.ä., wo man Infos aus dem Programm hineinschreibt. Und da kann man das Encoding ja leicht angeben.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

@Hyperion: Also ich finde das schon entscheidend. Ich sehe nicht wie man mit Python 3 und `print()` einfach Konsolenprogramme schreiben kann, die etwas ausserhalb von ASCII ausgeben. Damit ist das für mich nahezu unbrauchbar und dürfte letztlich vielleicht auch den ein oder anderen Einsteiger abschrecken der ein einfaches ``print('Hallöle')`` nicht zum Laufen bekommt.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

BlackJack hat geschrieben:@Hyperion: Also ich finde das schon entscheidend. Ich sehe nicht wie man mit Python 3 und `print()` einfach Konsolenprogramme schreiben kann, die etwas ausserhalb von ASCII ausgeben. Damit ist das für mich nahezu unbrauchbar und dürfte letztlich vielleicht auch den ein oder anderen Einsteiger abschrecken der ein einfaches ``print('Hallöle')`` nicht zum Laufen bekommt.
So gesehen hast Du recht.

Ist die Situation denn da wirklich so schlimm? Wovon geht Python denn da aus? Von seinem default encoding? Von utf-8? Ich habe Python 3 bisher kaum genutzt, daher hab mit mit print() quasi keine Erfahrung.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Antworten