Seite 1 von 1

UnicodeDecodeError bei Formularauswertung

Verfasst: Montag 26. Januar 2009, 15:35
von 0815pascal
Hallo miteinander, bin Python-Neuling und spiele gerade ein wenig damit rum. Ich will per Formular eine Wert weitergeben, der nacher ausgegeben werden soll. Dann bekomm ich allerdings die Fehlermeldung
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 7: ordinal not in range(128)
Der Code ist

Code: Alles auswählen

class checkAnswer(webapp.RequestHandler):
    def post(self):
        greeting = Greeting()
        usersolution = self.request.get('usersolution')
        self.response.out.write('''<html><body>''')
        self.response.out.write('''Deine Lösung ist %s''' %usersolution)
ich arbeite übrigens mit Google AppEngine, falls sich jmd. über webapp.RequestHandler wundern sollte.

Das PY-Dokument hab' ich als UTF-8 kodiert abgespeichert. Verstehe drum die Fehlermeldung nicht so ganz...

Verfasst: Montag 26. Januar 2009, 15:41
von DasIch
Da gibt es einen netten Wiki Artikel zu: [wiki]Von Umlauten, Unicode und Encodings[/wiki]

Verfasst: Montag 26. Januar 2009, 16:43
von 0815pascal
ich kenn' den Artikel bereits, aber versteh' nicht wirklich, was ich machen soll, bzw. was das problem ist.

Verfasst: Montag 26. Januar 2009, 17:22
von helduel
Dein Code stolpert über das 'ö' in Lösung. Wahrscheinlich versucht die write-Methode den nach UTF8 zu bringen, vergleichbar mit:

Code: Alles auswählen

"Deine Lösung".encode("utf-8")
Das geht schief, weil er vor dem Encoden versuchen muss, das ganze nach Unicode zu bringen - also den String erstmal zu dekodieren. Standardmäßig nimmt Python an, dass der String ein Ascii-String ist. Und weil's in Ascii kein ö gibt, gibt's eben die Exception.

Wahrscheinlich genügt es, wenn du einfach folgendes machst:

Code: Alles auswählen

class checkAnswer(webapp.RequestHandler):
    def post(self):
        greeting = Greeting()
        usersolution = self.request.get('usersolution')
        self.response.out.write('''<html><body>''')
        self.response.out.write(u'''Deine Lösung ist %s''' %usersolution)
Da du oben in deiner Python-Datei das Encoding, in dem die Datei geschrieben wurde, angegeben haben solltest, dekodiert Python es richtig und übergibt der write-Methode ein Unicode-Objekt, mit der es keine weiteren Probleme geben sollte.

Gruß,
Manuel

Verfasst: Montag 26. Januar 2009, 17:25
von kbr
Das PY-Dokument hab' ich als UTF-8 kodiert abgespeichert. Verstehe drum die Fehlermeldung nicht so ganz.
..

Die utf-8 Codierung bewirkt nur, dass Dein Editor den Quelltext im utf-8 Format abspeichert. Vor dem write-Aufruf musst Du den zu versendenen String als utf-8 encoden; schematisch:

Code: Alles auswählen

s = "Lösung".encode('utf8')
write(s)

Verfasst: Montag 26. Januar 2009, 17:56
von Hyperion
kbr hat geschrieben:
Das PY-Dokument hab' ich als UTF-8 kodiert abgespeichert. Verstehe drum die Fehlermeldung nicht so ganz.
..

Die utf-8 Codierung bewirkt nur, dass Dein Editor den Quelltext im utf-8 Format abspeichert. Vor dem write-Aufruf musst Du den zu versendenen String als utf-8 encoden; schematisch:

Code: Alles auswählen

s = "Lösung".encode('utf8')
write(s)
Das hilft aber noch nichts bei irgend welchen User-Eingaben! Die muss er ja vorher in Unicode decodieren ...

Generell gilt wie immer:
So früh wie möglich in Unicode wandeln und so spät wie möglich in einen Codec wandeln (und Nein, Unicode ist nicht uft-8 o.ä. - es hat bei mir auch lange gedauert, das zu kapieren :-D )

Also hier wäre es sinnvoll, die Usereingabe direkt zu decodieren und dann wie gezeigt später in z-b- utf-8 zu wandeln, bevor man etwas schreibt!

Verfasst: Montag 26. Januar 2009, 18:23
von kbr
hyperion hat geschrieben:Das hilft aber noch nichts bei irgend welchen User-Eingaben! Die muss er ja vorher in Unicode decodieren ...
Wenngleich es ursprünglich erst einmal um die Ausgabe ging, ist das natürlich korrekt; wobei beim decoden des Inputs wiederum das encoding des Formulars bekannt sein sollte ... genug der Verwirrung :)

Verfasst: Montag 26. Januar 2009, 19:38
von 0815pascal
hmm wenn ich

Code: Alles auswählen

u'''Deine Lösung ist"
schreibe, klappt halbwegs. Allerdings gibt es dann "Deine Lösung ist" aus. Das ö wird nicht richtig angezeigt

Versuche ich es mit

Code: Alles auswählen

s= "Lösung".encode('utf8')
write(s)
bekomme ich wieder die Meldung

UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 1: ordinal not in range(128)

Verfasst: Montag 26. Januar 2009, 19:51
von Leonidas
Weil man Bytestrings nicht enkodieren sondern eigentlich nur dekodieren kann (wenn du einen Bytestring enkodierst, wird er in Unicode mit dem Charset ASCII dekodiert und dann mit deinem gewünschten Charset dekodiert, was wegen dem ASCII eben fehlschlägt).

Verfasst: Montag 26. Januar 2009, 20:27
von tordmor
Der Fehler ist ein Decode-Error. Das bedeutet es wird versucht Binärdaten in unicode umzuwandeln. Das geschieht offensichtlich in self.response.out.write. Du übergibst ein Bytestring im ursprünglichen Code. Bytestrings werden unabhängig der codierung des Quelltextes versucht als ASCII zu decodieren, was fehlschlägt, da Umlaute in Ascii nicht definiert sind. Wenn Du keinen Bytestring sondern ein Unicodestring übergibst (später mit u""), klappt alles. Die fehlerhafte Anzeige im letzten Fall kommt daher, dass zwar der Unicodestring von Googleapps als utf-8 codiert wird, aber Dein Browser davon nichts mitbekommt. Das kannst Du ändern, indem du einen Content-Type header setzt (Content-Type: text/html; charset=utf-8), oder eine entsprechende meta-Angabe in den header der html-Datei setzt.

Verfasst: Montag 26. Januar 2009, 20:46
von str1442
Etwas mittels der u"..." in Unicode zu verwandeln klappt nur dann, wenn du das Encoding des Python Modules korrekt im Coding "Magic Comment" angegeben hast oder Python richtig geraten hat. Einfach deswegen, weil jeder String nunmal in der Datei in deren Encoding steht und dann mithilfe von u"..." in Unicode verwandelt werden würde beim Start des Interpreters. Unicode bekommt man nunmal nicht magisch.

Verfasst: Montag 26. Januar 2009, 22:44
von hendrikS
Ich muß zugeben, daß ich die Codiererei auch noch nicht so ganz durchschaut habe. Hatte neulich schon so ein Problem bei einer Lösung von Rebecca. Ich habe mal so was probiert.

Code: Alles auswählen

print "L"+u"\xF6"+"sung"
Vielleicht hilfts.

Jedenfalls interessant.

Verfasst: Montag 26. Januar 2009, 23:28
von hendrikS
Mit Wiki und PEP-263 habe ich jetzt noch folgende Variante gefunden, die unabhängig vom Editor sein sollte:

Code: Alles auswählen

# coding=iso-8859-1
print "Lösung".decode("iso-8859-1")

Verfasst: Montag 26. Januar 2009, 23:28
von BlackJack
Man kann u'L\xf6sung' aber auch echt umständlich schreiben. :-)

Edit: Nein das ist nicht unabhängig vom Editor. Der muss das nämlich auch noch in der angegebenen Kodierung speichern können.

Verfasst: Montag 26. Januar 2009, 23:41
von hendrikS
@BlackJack:
Danke für den Tip, wie man den String einfach aufschreibt.

Hinsichtlich Editor habe ich eben nochmal bei PEP-263 geguckt. Das sollte unabhängig vom Editor sein. Es gibt zwei Methoden:
1.)

Code: Alles auswählen

#coding=<encoding name>
2.)

Code: Alles auswählen

# -*- coding: <encoding name> -*-
So wie ich es verstanden habe, ist nur die zweite vom Editor abhängig. Aber vielleicht irre ich mich auch.

Verfasst: Dienstag 27. Januar 2009, 09:43
von Leonidas
Nein, das ist einfach nur die Vim* oder die Emacs-Syntax für die Angabe des Encodings, die auch vom Python-Interpreter ausgewertet werden kann.

* Jetzt davon mal abgesehen, dass Vim meistens die Modelines sowieso nicht auswertet.

Verfasst: Dienstag 27. Januar 2009, 10:32
von helduel
hendrikS hat geschrieben:Hinsichtlich Editor habe ich eben nochmal bei PEP-263 geguckt. Das sollte unabhängig vom Editor sein. Es gibt zwei Methoden:
Eigentlich gibt es Methoden wie Sand am Meer. Auch das funktioniert:

Code: Alles auswählen

#lsdkfjsdlkfjslfjkdljkfdksfdjsdlfkjcoding: utf-8 lsdkjflsdkjflsdkfj
:lol:
Es ist völlig Wurst, was in der Zeile steht, wichtig ist nur, dass in einer der ersten beiden Zeilen im Kommentar "coding: <coding>" steht. Alles andere drumherum ist egal.

Verfasst: Dienstag 27. Januar 2009, 11:37
von Hyperion
Ich habe den Eindruck, dass hendrikS nicht verstanden hat, dass zusätzlich zur Encoding-Angabe die Datei vom Editor eben noch in dem dort angegebenen Format gespeichert werden muss. Es nützt rein gar nichts da utf-8 reinzuschreiben, die Datei dann aber als ASCII zu speichern.

Verfasst: Dienstag 27. Januar 2009, 11:58
von hendrikS
Es ist völlig Wurst, was in der Zeile steht, wichtig ist nur, dass in einer der ersten beiden Zeilen im Kommentar "coding: <coding>" steht. Alles andere drumherum ist egal.[/quote]

Ja und Nein:

Das Drumherum ist egal sonst gibt es aber zwei Möglichkeiten der Zuweisung:
#coding: <coding>
#coding = <coding>

So geschrieben in PEP-263. Und geht auch so.

Langsam kommt jetzt bei mir hier etwas Licht ins Dunkel.
Auch, dass ich explizit im UTF-8 format speichern muss sofern UTF-8 Kodierung verwendet wird, wie schon einige hier angemerkt haben. Mein Editor unterstuetzt das Feature leider nicht.
Ist mir jetzt auch klar warum ich Rebeccas code aus einem anderen Thread neulich nicht sofort zum Laufen gebracht habe. Habe diesen jetzt mal im emacs kopiert und gespeichert. Läuft.
Wieder was gelernt. :D