leidiges Thema.. -> UTF-8 in Konsole

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
nepi
User
Beiträge: 23
Registriert: Montag 23. Juni 2008, 11:26

hallo...

Ich habe mir die einschlägigen Beiträge durchgelsen (http://www.python-forum.de/topic-4758.html), trotzdem glaube ich, dass ich einen "anderen" fehler habe, bzw. mir diese Lösung nicht hilft.. kann mich sehr gut täuschen :)

also...

Habe mein Programm unter pydev in eclipse erstellt, script (magic line), console, eclipse einstellungen -> alles ist auf utf-8, läuft bestens!
Nun wollte ich mein Programm auf einem 2. Rechner laufen lassen, geht auch alles, nur nutzt dieser 2. PC natürlich die cmd Konsole...
Dann ists heute passiert, ich bekam einen String (mein Programm holt Daten aus einer Webseite) mit ein paar der geliebten "komischen" zeichen. Mein Script erstellt aus diesem String einen sha-1 hex wert, diese methode scheiterte kläglich mit:

Code: Alles auswählen

UnicodeEncodeError: 'latin-1' codec can't encode character u'\u201a' in position
 64: ordinal not in range(256)
mein teil script (st ist der böse string):

Code: Alles auswählen

 s = sha.new()
s.update(st)
return "$"+s.hexdigest()
Das verrückte ist aber, das genau der GLEICHE string auf meinem normalen rechner mit pydev geht, ohne murren!!
Sprich mein Problem ist das Konsolen Encoding, kann mir aber nicht vorstellen, dass nur dies schuld ist, denn dies ist ja bloss eine Ausgabe, daher meine Frage:
-Wo muss ich was einstellen, damit sich python gleich verhält wie auf meinem 1. rechner? Sprich von latin-1 wie im fehler zu utf-8?
-Gibt es keinen Weg, der cmd Konsole utf-8 beizubringen? ohne umweg mit all dem encode gebastel wie im geposteten link...?

Specs:
pydev
python 2.5

danke euch viiielmals!!!
BlackJack

Der gezeigte Quelltext kodiert nirgends ein Unicode-Objekt, also kann es daran nicht liegen. Zeig doch mal den kompletten Traceback und den Quelltext der dazu passt. Da werden ja auch Zeilennummern und Zeilen drin auftauchen und das sind sicher nicht die drei Gezeigten.
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

nepi hat geschrieben:mein teil script (st ist der böse string):

Code: Alles auswählen

 s = sha.new()
s.update(st)
return "$"+s.hexdigest()
st.encode("utf-8") oder sowas machen.
TUFKAB – the user formerly known as blackbird
BlackJack

@mitsuhiko: Das wäre meine Idee gewesen, wenn die Ausnahme 'ascii' gesagt hätte, aber normalerweise sollte Python nicht auf die Idee kommen von sich aus 'latin-1' bei einer impliziten Kodierung zu verwenden.
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

BlackJack hat geschrieben:@mitsuhiko: Das wäre meine Idee gewesen, wenn die Ausnahme 'ascii' gesagt hätte, aber normalerweise sollte Python nicht auf die Idee kommen von sich aus 'latin-1' bei einer impliziten Kodierung zu verwenden.
Es gibt immer wieder Vögel die das default encoding auf latin1 ändern :wink:
TUFKAB – the user formerly known as blackbird
nepi
User
Beiträge: 23
Registriert: Montag 23. Juni 2008, 11:26

habe den string st nun mit encode nach utf-8 gebracht. und ging ohne murren. dennoch möchte ich gerne die ursache wissen, warum ich auf dem 2. rechner dies tun muss, und auf dem 1. nicht. bzw. was muss ich wo einstellen, damit sich python exakt gleihc verhält wie auf dem 1. rechner mit eclipse/pydev?
danke
BlackJack

Du musst das auf beiden Rechnern tun. Wenn Du das *nicht* tun musst, dann stimmt etwas nicht. Insbesondere sollte man das default encoding nicht ändern. Also was immer Du gemacht hast, das in der Fehlermeldung 'latin-1' anstelle von 'ascii' steht, solltest Du rückgängig machen.

Wenn Du nicht selbst explizit die `encode()`-Methode verwendest kannst Du nicht sicher sein, dass es auf allen Systemen funktioniert. Insbesondere ist eigentlich ASCII die Kodierung, die implizit bei einer Umwandlung verwendet wird. Das "kracht" also sonst bei jedem "Sonderzeichen".
lunar

mitsuhiko hat geschrieben:
BlackJack hat geschrieben:@mitsuhiko: Das wäre meine Idee gewesen, wenn die Ausnahme 'ascii' gesagt hätte, aber normalerweise sollte Python nicht auf die Idee kommen von sich aus 'latin-1' bei einer impliziten Kodierung zu verwenden.
Es gibt immer wieder Vögel die das default encoding auf latin1 ändern :wink:
Mal ganz dumme Frage: Wie macht man das? Bzw. was tun, wenn "sys.setdefaultencoding" einen AttributeError wirft?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

lunar hat geschrieben:
mitsuhiko hat geschrieben:Es gibt immer wieder Vögel die das default encoding auf latin1 ändern :wink:
Mal ganz dumme Frage: Wie macht man das? Bzw. was tun, wenn "sys.setdefaultencoding" einen AttributeError wirft?
Das kann man schlauerweise in ``site.py`` ändern bevor es in selbiger Datei gelöscht wird. Wenn du findest dass die Idee die Python-Installation zu hacken blöd ist - ganz recht, aber ich habe schon mehrere getroffen die auf diese glorreiche Idee kamen. Alternativ kann man in ``sitecustomize.py`` ähnlichen quatsch machen, da sie verarbeitet wird bevor ``setdefaultencoding`` gelöscht wird.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
lunar

Zumindest in ipython wäre das ganz nützlich ... UTF-8 als Input-Encoding und ASCII als Unicode-Encoding vertragen sich nicht sonderlich gut: Unicode-Literale in Ipython sind bei mir so gut wie nutzlos, weil Umlaute falsch dekodiert werden.
Zuletzt geändert von lunar am Freitag 8. August 2008, 12:04, insgesamt 1-mal geändert.
nepi
User
Beiträge: 23
Registriert: Montag 23. Juni 2008, 11:26

hallo miteinander...

Ihr hattet recht, mein default encoding war auf latin-1, wusste dies nicht, habe die python config so übernohmen wie sie war.. ist nun auf ascii eingestellt. ein sitecustomize.py habe ich aber gar nicht gefunden.

habe leider immer noch ein problem:

ausgangslage:
mein script habe ich erweitert mit folgenden funktionen wie sie hier empfohlen werden (http://gerold.bcom.at/python/python_anl ... mandozeile), sprich habe jetzt encode funktionen, die mir meine utf-8 strings im programm nach stdout encoding umwandeln.

In der cmd.exe Konsole funktioniert dies wunderbar, dabei sind folgende codings aktiv:
default encoding: ascii
script encoding: utf-8
stdout encoding: cp1252 ((cp65001 als cp für utf-8 geht nicht in python, stürtzt ab mit folgender meldung:

Code: Alles auswählen

*** default encoding: ascii
*** stdout  encoding: cp65001
blüüüTraceback (most recent call last):
  File "mpController.py", line 60, in <module>
    print "blüüü"
IOError: [Errno 3] No such process
))

In eclipse werden die umgewandelten strings *nicht* richitg angezeigt, sonderzeichen erhalten ein '?', dabei sind folgende codings aktiv:
default encoding: us-ascii (eingestellt in 'open run dialog' -> 'common' tab -> 'console encoding')
script encoding: utf-8
stdout encoding: mbcs
(mbcs kommt von sys.getfilesystemencoding(), da eclipse stdout ja umleitet)
Aus diesem Grund habe ich die eclipse konsole nun auf cp1252 eingestellt, damit ich vernünftig arbeiten kann. So werden wieder alle umgewandelten Zeichen korrekt dargestellt.

Zusammenfassung:
cmd.exe und eclipse console (mit cp1252 default encoding) stellen mir alle sonderzeichen *korrekt* dar, sofern ich sie mit der convert funktion mutiere bevor ich sie ausgebe.

problem:
In meinem script bekomme ich strings aus dem internet (extrahiere text aus internetseiten). Diese stelle ich dar (log/print/weiterverarbeitung). Die Internetseite hat ein utf-8 encoding. Die dargestellten strings im script sind in eclipse korrekt, jedoch sehe ich in cmd.exe nur komische zeichen (sprich können nicht dargestellt werden)
An was kann das liegen? Sonderzeichen (éèç€) direkt im script per convert funktion sehen ich ja perfekt in cmd.exe...

specs:
Python 2.5
pydev 1.3.17/18
magicline ist utf-8
site.py code:

Code: Alles auswählen

    encoding = "ascii" # Default value set by _PyUnicode_Init()
    if 0:
        # Enable to support locale aware default string encodings.
        import locale
        loc = locale.getdefaultlocale()
        if loc[1]:
            encoding = loc[1]
    if 0:
        # Enable to switch off string to Unicode coercion and implicit
        # Unicode to string conversion.
        encoding = "undefined"
    if encoding != "ascii":
        # On Non-Unicode builds this will raise an AttributeError...
        sys.setdefaultencoding(encoding) # Needs Python Unicode build !
vielen dank...[/code]
BlackJack

Also erst einmal würde ich das mit der `site.py` sein lassen. Die Default-Kodierung sollte immer ASCII sein, wenn man die ändert, schafft man sich nur Probleme.

Und dann musst Du halt immer entsprechend Kodieren, je nach dem was Du oder das empfangende Programm haben möchte. Da man das nicht immer "erraten" kann, sollte man entweder eine Kodierung fest wählen, zum Beispiel UTF-8 weil damit alle Unicode-Zeichen kodiert werden können, oder man verpasst dem Programm mindestens eine Option, damit der Benutzer eine Kodierung wählen kann. Am besten noch eine zweite, mit der man das Verhalten steuern kann, falls etwas nicht korrekt kodiert werden kann.
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

lunar hat geschrieben:
mitsuhiko hat geschrieben:
BlackJack hat geschrieben:@mitsuhiko: Das wäre meine Idee gewesen, wenn die Ausnahme 'ascii' gesagt hätte, aber normalerweise sollte Python nicht auf die Idee kommen von sich aus 'latin-1' bei einer impliziten Kodierung zu verwenden.
Es gibt immer wieder Vögel die das default encoding auf latin1 ändern :wink:
Mal ganz dumme Frage: Wie macht man das? Bzw. was tun, wenn "sys.setdefaultencoding" einen AttributeError wirft?
Ganz einfach: ``reload(sys)``.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
nepi
User
Beiträge: 23
Registriert: Montag 23. Juni 2008, 11:26

bin nun weitergekommen...

@blackjack, jo natürlich lasse ich nun das defaultencoding auf ascii :) ist sicher das sauberste so...

den beschriebenen fehler verursachte die log library in cmd.exe, daher wurde jeder string falsch geschrieben. Wenn ich nun die Strings, welche ich von html seiten extrahiere mit einem simplen print ausgebe, habe ich alle sonderzeichen. Dies jedoch zur meiner grossen Verwunderung *ohne* die convert funktion (convert funktion = string.decode(scriptencoding).encode(stdoutencoding)). Sprich ich gebe wirklich direkt den extrahierten string mit print aus. Wenn ich diesen mit der convert funktion ausgebe, erhalte ich einen UnicodeEncode Fehler. Hingegen *muss* ich jeden anderen string, welchen ich im script deklariere und sonderzeichen enthält mit der convert funktion ausgeben um keinen fehler zu erhalten.

In der eclipse Konsole ist bei mir jeder string korrekt, solange ich das console encoding auf cp1252 habe.

Das weiter verwunderliche für mich ist, das die funktion welche ich im 1. post beschrieben habe fehlschlägt mit dem string aus der internetseite (mit und ohne convert).
Funktion:

Code: Alles auswählen

st = meinInternetString
s = sha.new()
s.update(st)
return "$"+s.hexdigest()
Aber wenn ich diesen string (st) vor dem s.update() noch so encodiere

Code: Alles auswählen

cleanedString = st.encode("cp1252")
geht es ohne probleme... (cp1252 ist dann schon ne variable mit sys.stdout.encoding)

Zusammenfassung der Probleme/Merkwürdigkeiten:
- Log Lib kann bei mir in der cmd.exe keine sonderzeichen darstellen wenn defaulencoding ascii ist
- extrahierte strings aus einer Internetseite werden ohne convert korrekt dargestellt in cmd.exe (sofern codepage 1252 ist)
- jedoch sind diese strings nicht zu gebrauchen für eine weiterverarbeitung (z.b. sha.update()), da ich so einen Unicode error bekomme, erst mit einem encode(sys.out.encoding) gehts..

Meiner Meinung nach muss es dem sha.update() doch egal sein, was für ein stdout encoding ich habe, es muss nur den internen bytestring verarbeiten. der stdout hat damit doch nichts zu tun, das ist nur ausgabe. ob der string aus der internetseit nun utf-8, iso-8859-1 oder ascii ist spielt doch keine rolle... ein string weiss nichts über sein encoding, warum muss ich also diesem string 'st' das encoding meines stdout mitgeben damits geht?
vielen dank euch... (glaube langsam echt versteh nur noch bahnhof..)
BlackJack

So wie Du das beschreibst bekommst Du aus den Internetseiten keine Zeichenketten, sondern `unicode`-Objekte. Sonst würde `encode()` mit cp1252 auch gar nicht funktionieren. Und das erklärt auch alles andere.
nepi
User
Beiträge: 23
Registriert: Montag 23. Juni 2008, 11:26

danke für deine antwort..

genau das nehme ich mittlerweile auch an..
jedoch ergab ein test-code, dass es ein bytestring ist. bin mir aber nicht sicher wie vertrauchlich dieser test ist..

Code: Alles auswählen

x = testString
if isinstance(x, str):
    print "string"
elif isinstance(x, unicode):
    print "unicode"
(link mit testmöglichkeiten http://mail.python.org/pipermail/python ... 17768.html )

aber wie du gesagt hast, wenn auf ein objekt direkt ein encode() anwendbar ist, kann es sich de facto nur um ein unicode objekt handeln..
BlackJack

Bau doch einfach ein ``print type(obj)`` ein, um Gewissheit zu erlangen. Aber Achtung: Es gibt Bibliotheken, die bei XML/HTML nur dann `unicode`-Objekte liefern, wenn das auch wirklich notwendig ist, also irgend etwas ausserhalb von ASCII drin vorkommt.
Antworten