Seite 1 von 2

Allgemeine Lösung für Umlautprobleme?

Verfasst: Freitag 14. Juli 2006, 11:55
von gerold
Hi!

Mich ärgert es immer wieder, wie umständlich man bei Python mit Umlauten umgehen muss. Überhaupt dann, wenn man Programme für Windows, Linux und Cygwin schreiben möchte UND diese eventuell auch mit cx_freeze oder py2exe packen möchte.

Dann gibt es noch die verschiedensten Editoren, Interpreter und IDEs in denen die Programme ja auch laufen sollten. (python, ipython, PyShell, IDLE, WingIDE,...)

Ich habe zwar den Hinweis bekommen, dass Python versucht, beim Schreiben in die Konsole das richtige Encoding zu verwenden wenn man einen Unicode-String übergibt, aber das funktioniert bei mir die meiste Zeit NICHT. Auf dieses anscheinend willkürliche Verhalten bei Unicode-Strings kann ich nicht setzen.

Deshalb habe ich mich mit einem Workaround befasst, der in den meisten Fällen funktionieren sollte. Allerdings ist dieser Ersatz ziemlich umständlich und ich kann ihn auch nicht überall testen. Aber zumindest habe ich es versucht.

Unten stehender Code wurde von mir bereits unter folgenden Bedingungen getestet:

- Windows 2000 - Python 2.4.3
- Windows 2000 - Python 2.4.3 - IDLE 1.1.3
- Windows 2000 - Python 2.4.3 - WingIDE 2.1.0-1
- Windows 2000 - Cygwin - Bash 3.0 - Python 2.4.1 (GCC)
- Windows 2000 - Cygwin - Bash 3.0 - Python 2.4.3 (MSC)
- Debian 3.1 Linux (locale: de_AT@euro) - Python 2.3.5
- Debian 3.1 Linux (locale: de_AT@euro) - Python 2.4.1
- Gentoo linux (local: de_AT.utf8) - Python 2.4.2 - (# -*- coding: utf-8 -*-)

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-

# Lizenz: ohne Einschränkungen frei

import os
import sys
import codecs
# Imports für cx_freeze:
import encodings, encodings.ascii, encodings.utf_8, \
    encodings.iso8859_1, encodings.iso8859_15
try:
    import encodings.mbcs, encodings.cp850
except:
    pass


# sys.stdout umleiten, damit Umlaute korrekt angezeigt werden.
#(funktioniert auch mit Idle und cx_freeze)
out_enc = ""
if sys.platform.startswith("win"):
    out_enc = getattr(sys.stdout, "encoding", None) or \
        sys.getfilesystemencoding() or "cp850"
elif sys.platform.startswith("linux"):
    out_enc = getattr(sys.stdout, "encoding", None) or \
        sys.getfilesystemencoding() or \
        os.popen("locale | grep 'LC_MESSAGES'").read().strip().split("=")[1]
else:
    out_enc = getattr(sys.stdout, "encoding", None) or \
        sys.getfilesystemencoding() or ""
if out_enc.upper() in ("", "ASCII", "US-ASCII", "ANSI_X3.4-1968", "POSIX"):
    out_enc = "raw_unicode_escape"
sys.stdout = codecs.getwriter(out_enc)(sys.stdout)


if __name__ == "__main__":
    # testen
    print "out_enc:", out_enc
    print u"printtest öäüß"
    sys.stdout.write(u"stdouttest: äüöß\n")
Bitte probiert diesen Code mit eurem Betriebssystem aus und teilt mir mit, ob es damit Probleme gibt. Vielleicht weiß jemand auch eine bessere Lösung --> dann sagt sie mir. Bitte! Ich suche schon lange nach einer guten Lösung. :roll: Auch wenn ich mich damit blamiere, aber ich habe bis auf oben stehende Lösung noch nicht raus bekommen, wie man es besser machen könnte.

lg
Gerold
:-)

PS: Für sys.stderr habe ich noch überhaupt keine Lösung gefunden. Gibt es eine allgemein verwendbare Möglichkeit, das Encoding von sys.stderr raus zu bekommen?

- Edit: try-except um einen Import gelegt.
- Edit: Sonderfälle abgefangen
- Edit: .split("=")[1] hinzugefügt
- Edit: "POSIX" hinzugefügt
- Edit: auch für Linux ein sys.getfilesystemencoding() eingebaut
- Edit: "cygwin" raus geschmissen, da es von den Ausnahmefällen abgedeckt wird.
- Edit: Ab jetzt wird bei unbekannten Betriebsystemen zumindest versucht, das Encoding raus zu bekommen.

Verfasst: Freitag 14. Juli 2006, 12:13
von gerold
...
Oben stehenden Code habe ich unter Windows 2000 auch mit cx_freeze ausprobiert.

Zum Freezen habe ich folgende Batch-Datei verwendet:

Code: Alles auswählen

REM  --------------------------------------------------
REM   Erstellt aus dem PYTHONFILE eine ausführbare EXE
REM  --------------------------------------------------

SET PROJECTDIR="C:\Dokumente und Einstellungen\Gerold\Desktop\umlauttest"
SET PYTHONFILE="umlauttest.py"

CD /D %PROJECTDIR%

DEL %PROJECTDIR%\bin\win\msvcr71.dll
DEL %PROJECTDIR%\bin\win\python24.dll
DEL %PROJECTDIR%\bin\win\umlauttest.exe

CP %SystemRoot%\system32\msvcr71.dll %PROJECTDIR%\bin\win\

FreezePython.exe --install-dir=%PROJECTDIR%\bin\win %PYTHONFILE%

PAUSE
Zumindest auf dem gleichen Computer lässt sich das Programm in der Konsole aufrufen und liefert korrekt angezeigte Umlaute.

lg
Gerold
:-)

Verfasst: Freitag 14. Juli 2006, 12:17
von Leonidas
Nachdem ich encodings.mbcs auskommentiert habe (das kommt davon wenn man irgendwelche unnötigen Module importiert nur um Freezer glücklich zu machen) lief es bei mir auch, zumindest auf meinem Ubuntu. Auf dem Debian ging es nicht, dort dam als Out-Encoding aber immerhin ANSI_X3.4-1968 raus.

Systeme:
Ubuntu Linux 6.06 (locale: en_AU.UTF-8) - Python 2.4.3
Debian GNU/Linux 3.1 (locale: POSIX) - Python 2.4.3

Verfasst: Freitag 14. Juli 2006, 12:25
von gerold
Hi Leonidas!
Leonidas hat geschrieben:Nachdem ich encodings.mbcs auskommentiert habe
Das kommt davon, wenn ich nach dem Testen noch ein paar Module importiere... :? Ich werde wohl noch ein try-except einbauen müssen.

Leonidas hat geschrieben:Auf dem Debian ginbg es nicht, dort dam als Out-Encoding aber immerhin ANSI_X3.4-1968 raus.
[...]Debian GNU/Linux 3.1 (locale: POSIX) - Python 2.4.3

Was könnte man tun, damit es unter Linux auch dann noch funktioniert, wenn als "locale" *POSIX* eingestellt ist?

lg
Gerold
:-)

Verfasst: Freitag 14. Juli 2006, 12:35
von Damaskus
Windows XP - Python 2.4.3
Windows XP - Python 2.4.3 - IDLE
Windows XP - Python 2.4.3 - WingIDE 2.1.x

funktioniert. Mit Windows Vista werd ichs am Wochenende mal testen.

Gruß
Damaskus

Verfasst: Freitag 14. Juli 2006, 12:37
von Rebecca
Unter Suse 10.0 mit Python 2.4.1 und mit LANG=en_US.UTF-8 klappts.
Unter Slax 5.1.6 kam als Out-Encoding auch immer ANSI_X3.4-1968 raus. Allerdings ist dort LANG=en_US, und locale.getdefaultlocale() liefert (None, None) :?:.

Du solltest noch irgendwas fuer den Fall tun, dass man was anderes als die vorgesehenen Betriebssysteme benutzt. Denn NameError: name 'out_enc' is not defined ist irgenwie bloed...

Verfasst: Freitag 14. Juli 2006, 12:50
von gerold
Rebecca hat geschrieben:Unter Slax 5.1.6 kam als Out-Encoding auch immer ANSI_X3.4-1968 raus. Allerdings ist dort LANG=en_US, und locale.getdefaultlocale() liefert (None, None) :?:.

Du solltest noch irgendwas fuer den Fall tun, dass man was anderes als die vorgesehenen Betriebssysteme benutzt. Denn NameError: name 'out_enc' is not defined ist irgenwie bloed...
Hi!

@Leonidas, Damaskus, Rebecca: Danke schon mal fürs testen.

@Leonidas, Rebecca: Bitte noch einmal ausprobieren? Ich habe etwas eingebaut, was ich nicht testen kann. Bei mir sind überall "locales" eingestellt.

lg
Gerold
:-)

Verfasst: Freitag 14. Juli 2006, 13:10
von Rebecca
Cool, unter Slax geht's jetzt. out_enc ist nun raw_unicode_escape. Das ganze ist uebrigens Python 2.4.1.

Verfasst: Freitag 14. Juli 2006, 13:32
von gerold
Rebecca hat geschrieben:Cool, unter Slax geht's jetzt.
Merci :-)

Verfasst: Freitag 14. Juli 2006, 14:31
von Leonidas
Naja, jetzt wird das Programm zwar nicht durch eine Exception beendet, sondern es kommt raw_unicode_escape. Dann kommen die Zeichen, die aber dann als Kästchen mit Fragezeichen dargestellt werden - könnte auch eine Inkompatibilität mit dem Encoding von dem Rechner auf dem ich SSH ausführe.

Dafür funktioniert print 'äöü' im Interpreter dagegen tadellos.

Verfasst: Freitag 14. Juli 2006, 15:01
von gerold
Leonidas hat geschrieben:Kästchen mit Fragezeichen
[...]
Dafür funktioniert print 'äöü' im Interpreter dagegen tadellos.
Hi Leonidas!

Vielen Dank für den Test. Allerdings weiß ich nicht, was ich verändern könnte, damit es besser funktioniert.

Wenn du Umlaute siehst, dann liegt es wahrscheinlich nicht an der Schrift. Mehr fällt mir aber dazu auch nicht ein. Du verwendest ein Encoding, das mit Umlauten nichts anfangen kann, kannst aber trotzdem Umlaute sehen... verstehen tu ich es nicht.

Ich bitte weiterhin alle hier im Forum, sich daran zu beteiligen und einen Tipp abzugeben, wie es besser laufen könnte, was man verbessern und verändern könnte.

lg
Gerold
:-)

Verfasst: Freitag 14. Juli 2006, 15:29
von Rebecca
Hab das ganze mal auf AIX laufen lassen :twisted: . Bekomme dann natuerlich auchraw_unicode_escape, und statt der vier Umlaute zwei Kaestchen. Da ich mich per ssh eingeloggt habe, habe ich gedacht, vielleicht geht irgendwo zwischen meinem xterm und der AIX-Shell was verloren. Ich kann aber in der Shell per echo und im Interpreter per print Umlaute ausgeben lassen. Ich bekomme allerdings den Quellcode nicht richtig angezeigt (auch immer mit Kaestchen an den entprechenden Stellen), weder mit more noch mit Emacs oder vi. Im Emacs bekomme ich auch manuell ueberhaupt keine Sonderzeichen zustande.

Python-Version ist 2.2, locale.getdefaultlocale liefert ['en_US', 'ISO8859-1'].

Naja, dieses daemliche AIX geht mir sowieso total auf die Nerven. :?

So, jetzt geht's ab ins Wochenende! 8)

Verfasst: Freitag 14. Juli 2006, 19:39
von gerold
Rebecca hat geschrieben:Hab das ganze mal auf AIX laufen lassen
Hi Rebecca!

Was bekommst du zurück, wenn du ``sys.platform`` eingibst?
Normalerweise könnte ich dieses OS ja sicher gleich wie Linux behandeln. Wenn ich weiß, was bei ``sys.platform`` raus kommt, dann mach ich das.

Bei ``ISO8859-1`` könnte das funktionieren.

lg
Gerold
:-)

Verfasst: Samstag 15. Juli 2006, 14:57
von CrackPod
(K)ubuntu 5.10; KDE: 3.5.0; Kernel 2.6.12-10-686; Architektur: i686

Code: Alles auswählen

IDLE 1.1.2      
>>> ================================ RESTART ================================
>>> 
out_enc: utf-8
printtest öäüß
stdouttest: äüöß

Code: Alles auswählen

$ python UmlauteTest.py
out_enc: UTF-8
printtest öäüß
stdouttest: äüöß
Also ein Terminal und IDLE Test.
Wie kann ich das dann in meine Programme einfügen? Kann ich das als Modul importieren oder muss ich das an den Anfang von jedem Programm schreiben?
Und noch ne Frage: Lässt sich das auch als Lösung für eine Eingabe verwenden? Dann gibts keine Probleme mehr dafür
Greetz

Verfasst: Samstag 15. Juli 2006, 18:33
von gerold
CrackPod hat geschrieben:(K)ubuntu 5.10; KDE: 3.5.0; Kernel 2.6.12-10-686; Architektur: i686
[...]
Kann ich das als Modul importieren?
[...]
Lässt sich das auch als Lösung für eine Eingabe verwenden?
Hi CrackPod!

Danke, für den Test.

Ja, es lässt sich einfach als Modul importieren. Und wenn man kein cx_freeze einsetzt, dann kann man die speziellen Imports für cx_freeze auch weg lassen.

Das ist noch keine Lösung für sys.stdin oder sys.argv. Allerdings habe ich vor, sobald ich herausgefunden habe, ob das hier eine gute Lösung ist, auch sys.stdin so umzuleiten.

sys.stderr ist irgendwie ein Sonderfall. Da bekomme ich meistens kein Encoding dafür raus. Du siehst, es wird noch ein Weilchen dauern bis es eine Lösung wird, die man allgemein empfehlen kann. Vielleicht ist in Python auch schon alles eingebaut was man braucht und ich habe es nur noch nicht kappiert. -- Das kann auch noch sein.

lg
Gerold
:-)