Umlaute und die Kommandozeile

Gute Links und Tutorials könnt ihr hier posten.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Mittwoch 28. Dezember 2005, 14:40

Schreiben von Umlauten in die Konsole -- Lesen von Umlauten aus der Kommandozeile

Das Problem beim Übergeben von Texten an die Konsole ist, dass das Coding der Konsole nicht unbedingt mit dem im Skript verwendeten Coding überein stimmen muss. Mir ist aufgefallen, dass die Python-Programm unter Linux meist mit dem gleichen Coding erstellt werden, mit dem auch die Konsole läuft. Das ist aber unter Windows ziemlich selten der Fall.

Um beim Schreiben in die Konsole auch das richtige Coding zu verwenden, muss man vorher herausfinden welches Coding verwendet werden soll. Das funktioniert mit dem Befehl sys.stdout.encoding. Es kann vorkommen, besonders wenn man das Skript aus einer IDE heraus aufruft, dass dieser Befehl nichts zurück gibt. Dann kann man es ja noch mit sys.getfilesystemcoding() versuchen.

Leider ist es unter Python nicht so einfach einen Text in ein bestimmtes Coding umzuwandeln. Man muss immer vorher den Text, vom im Skript verwendeten Coding, nach Unicode umwandeln. Erst danach kann man den Unicode-String in das gewünschte Ziel-Coding umwandeln.

Zum Umwandeln nach Unicode kann man die String-Methode decode() verwenden. Zum Umwandeln von Unicode in das gewünschte Ziel-Coding kann man die Methode encode() verwenden.

Also, noch einmal, weil es so wichtig ist: Mit decode() wird ein Text nach Unicode umgewandelt und mit encode() wird dieser Unicode-String in das gewünschte Ziel-Coding umgewandelt.

Jetzt müssen wir nur noch herausfinden, von welchem Coding wir den Text in den Unicode-String umwandeln müssen. Das mache ich mir persönlich ziemlich einfach. Ich habe meistens in meinen Python-Modulen eine Variable mit dem Namen SCRIPTCODING, die ich auf das Coding meines Skriptes setze. Man muss nur darauf achten, dass man diese Variable beim Ändern des Script-Codings auch verändert.

Code: Alles auswählen

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

import sys

SCRIPTCODING = "iso-8859-1"
FSCODING = sys.stdout.encoding or sys.getfilesystemencoding()
Noch ein wichtiger Hinweis! Wenn man das Coding am Anfang des Moduls mit # -*- coding: definiert, dann muss man dieses Coding auch verwenden. Wenn man dem Python-Interpreter mit # -*- coding: utf-8 -*- mitteilt, dass das Skript als UTF-8-Datei abgespeichert wurde, dann muss man sich auch daran halten und die Datei auch wirklich als UTF-8-Datei abspeichern. Der Editor Wing-IDE liest das definierte Coding aus und speichert die Datei automatisch in diesem Format ab. Das ist bei anderen Editoren nicht selbstverständlich und viele können mit UTF-8 überhaupt nicht umgehen. Um unter Windows zu prüfen, in welchem Coding ein Python-Modul abgespeichert wurde, kann man dieses im Editor "Notepad", dem Standardeditor von Windows öffnen. Wenn man dann im Menü Datei auf Speichern unter... klickt, dann sieht man, mit welchem Coding der Editor dieses Skript abspeichern würde. Bei UTF-8-Dateien wird im Speichern-Dialog UTF-8 angezeigt.

Und so könnte das komplette Skript aussehen:

Code: Alles auswählen

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

import sys
import types

SCRIPTCODING = "iso-8859-1"
FSCODING = sys.stdout.encoding or sys.getfilesystemencoding()


#----------------------------------------------------------------------
def to_fscoding(text = ""):
    """
    Wandelt Text vom Coding des Skriptes in das
    Kommandozeilen-Coding um.
    """

    if isinstance(text, types.StringTypes):
        if text:
            try:
                text = text.decode(SCRIPTCODING)
                text = text.encode(FSCODING)
            except:
                pass

    return text


#----------------------------------------------------------------------
def to_scriptcoding(text = ""):
    """
    Wandelt Text vom Coding der Kommandozeile in das
    Script-Coding um.
    """

    if isinstance(text, types.StringTypes):
        if text:
            try:
                text = text.decode(FSCODING)
                text = text.encode(SCRIPTCODING)
            except:
                pass

    return text


#----------------------------------------------------------------------
def pnt(message = ""):
    """
    Helferprozedur um den Befehl zum Schreiben
    in die Konsole ein wenig abzukürzen.
    Aus ``print to_fscoding(message)`` wird ``pnt(message)``.
    """

    print to_fscoding(message)


#----------------------------------------------------------------------
def main():
    """Hauptprozedur"""

    # Im Skript definierter Text
    message = "Das ist ein Text mit Umlauten (öäüß)"
    pnt(message)

    # Zahl
    message = 12345
    pnt(message)

    # Von der Kommandozeile entgegen genommener Text
    if len(sys.argv) > 1:
        message = to_scriptcoding(sys.argv[1])
        pnt(message)


#----------------------------------------------------------------------
if __name__ == "__main__":
    main()
Das Original dieser Anleitung ist auf meiner Website zu finden.

Weiterhin viel Spaß beim Programmieren mit Python!
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
jens
Moderator
Beiträge: 8482
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Mittwoch 28. Dezember 2005, 16:45

Das wäre eigentlich eine Prima Seite im Wiki!
(Ich weiß, du magst keine Wikis :cry: )

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
henning
User
Beiträge: 274
Registriert: Dienstag 26. Juli 2005, 18:37

Mittwoch 28. Dezember 2005, 16:57

Vielleicht sollte man noch erwähnen, dass es auch eine gute und anerkannte Praxis ist, strings zur Laufzeit als unicode zu speichern.

Das ist unabhängig von dem encoding der Quellcodedatei, welches sich auf "literarische" Strings bezieht.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Mittwoch 28. Dezember 2005, 17:10

jens hat geschrieben:Das wäre eigentlich eine Prima Seite im Wiki!
(Ich weiß, du magst keine Wikis :cry: )
Hi Jens!

Ich mag Wikis. Ich mag nur die typische Wiki-Syntax nicht. :)

Ich werde es rein stellen, sobald die Anleitung ausgereift ist und ich raus gefunden habe, wie ich ins Wiki etwas mit "reStructuredText" schreiben kann.

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Mittwoch 28. Dezember 2005, 17:24

henning hat geschrieben:Vielleicht sollte man noch erwähnen, dass es auch eine gute und anerkannte Praxis ist, strings zur Laufzeit als unicode zu speichern.

Das ist unabhängig von dem encoding der Quellcodedatei, welches sich auf "literarische" Strings bezieht.
Hi Henning!

Nur damit ich dich richtig verstehe. Du meinst also, jeder String im Skript sollte kein normaler String sondern ein Unicode-String sein.

Ich habe das bis jetzt immer mit dem lästigen "u" vor dem String verbunden.

Code: Alles auswählen

message = u"Das ist ein Text mit Umlauten (öäüß)"
Da ich in meinen Skripten ziemlich viele Statusmeldungen ausgebe, habe ich recht schnell mal ein paar hundert Strings, die ich immer mit "u" kennzeichnen müsste. Ist das richtig so, oder gibt es eine bessere Möglichkeit?

Du sprichst von dieser Vorgehensweise, richtig?

Code: Alles auswählen

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

import sys

FSCODING = sys.stdout.encoding or sys.getfilesystemencoding()

s = u"Umlaute (äüö)"
print s.encode(FSCODING)

if len(sys.argv) > 1:
    s = sys.argv[1].decode(FSCODING)
    print s.encode(FSCODING)
Poste doch bitte mal ein kleines Beispiel. Wenn es praktischer ist, dann ändere ich das Tutorial so um, dass als Basis immer Unicode verwendet wird.

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
henning
User
Beiträge: 274
Registriert: Dienstag 26. Juli 2005, 18:37

Samstag 31. Dezember 2005, 11:54

gerold hat geschrieben: Nur damit ich dich richtig verstehe. Du meinst also, jeder String im Skript sollte kein normaler String sondern ein Unicode-String sein.
Nein ich meine, dass Daten die du von "aussen" kriegst, oder dahin schicken willst intern eigentlich als unicode gehandelt werden sollten, weil du ja nie weißt in welchem Land dein Programm läuft und was du so für komische Zeichen kriegst, die an anderen stellen dann wieder probleme machen. unicode ist da halt die "universellste" Lösung.
Im Grunde spricht ja trotzdem nichts dagegen, "feste" strings, dem file-encoding entsprechend anzulegen, dafür ist es ja da, man müsste es dann nur zu unicode machen, wenn mans mit anderem unicode komibiniert, is klar...

Aber wenn ich ehrlich bin, halte ich mich eigentlich auch nie dran, weil ich viel nur für mich oder Einzelanwender aus dem deutschsprachigen Raum schreibe. Ich habs halt mal irgendwo gehört/gelesen.

Für ein Beispiel hab ich grad keine Zeit, vielleicht ist ja so klar geworden was ich meine, wenn nicht nochmal kurz n post.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Montag 2. Januar 2006, 08:53

gerold hat geschrieben:Ich werde es rein stellen, sobald die Anleitung ausgereift ist und ich raus gefunden habe, wie ich ins Wiki etwas mit "reStructuredText" schreiben kann.
Hi Jens!

Bin einen Schritt weiter: reStructuredText

Jetzt muss ich nur noch herausfinden, ob meine, im Tutorial beschriebene, Vorgehensweise auch pythonisch ist. Falls ich damit totalen Blödsinn verzapft habe, dann lösche ich die Anleitung wieder.

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

Montag 2. Januar 2006, 20:39

gerold hat geschrieben:Ich werde es rein stellen, sobald die Anleitung ausgereift ist und ich raus gefunden habe, wie ich ins Wiki etwas mit "reStructuredText" schreiben kann.
Kann man: http://pythonwiki.pocoo.org/GeroldPenz
TUFKAB – the user formerly known as blackbird
Benutzeravatar
jens
Moderator
Beiträge: 8482
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Dienstag 10. Januar 2006, 08:37

@gerold: Deine Information kannst du vielleicht bei http://pythonwiki.pocoo.org/Unicode reinsetzten...

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Dienstag 10. Januar 2006, 10:49

jens hat geschrieben:@gerold: Deine Information kannst du vielleicht bei http://pythonwiki.pocoo.org/Unicode reinsetzten...
Hi Jens!

Mein Problem ist, dass diese Information nicht richtig ist. Es wird empfohlen, Strings innerhalb des Skriptes nach Unicode zu konvertieren und vor der Ausgabe wieder in das Coding der Konsole umzuwandeln.

Mit meiner Empfehlung verstoße ich also grob gegen andere Empfehlungen. Ausgereift ist es auch noch nicht, da ich beim Umwandeln nicht prüfe ob der String evt. schon Unicode ist oder nicht. Ich bin sogar kurz davor, meine Anleitung wieder zu löschen, da sie von der reinen Lehre abweicht.

Ich bräuchte noch ein paar Rückmeldungen, hier im Forum.

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
jens
Moderator
Beiträge: 8482
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Dienstag 10. Januar 2006, 13:26

gerold hat geschrieben:Mein Problem ist, dass diese Information nicht richtig ist. Es wird empfohlen, Strings innerhalb des Skriptes nach Unicode zu konvertieren und vor der Ausgabe wieder in das Coding der Konsole umzuwandeln
Naja, ich weiß es auch nicht so recht... Normalerweise kommt man immer ganz gut weg, wenn man einfach nicht's macht ;) Also wenn man ein # -*- coding: UTF-8 -*- macht, dann wird halt alles automatisch in UTF-8 gehandhabt und fertig :)
So verfahre ich bei PyLucid bisher ganz gut ;) Allerdings hab ich bemerkt, das ich z.B. die Daten für ein simpleTAL-Template durchaus vorher in unicode wandeln muß :?

Ich denke es ist die Frage was man im konkreten Fall benötigt... In deinem Fall war es: Schreiben von Umlauten in die Konsole -- Lesen von Umlauten aus der Kommandozeile
Ich frage mich nur, ob man nicht auch einfacher stdin und stdout mit einem encode/decode versehen kann??? Wäre doch viel einfacher, oder?

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Moderator
Beiträge: 8482
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Freitag 20. Januar 2006, 09:01

Also ich komm irgendwie auf keinen grünen Zweig... Und zwar ist es so:

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: UTF-8 -*-

import sys, os

OUTCODING = sys.stdout.encoding or sys.getfilesystemencoding()

print "outencoding:", OUTCODING
print

test = u"testäöüß"
print "ohne:", test
print "mit:", test.encode(OUTCODING)

print "-"*70

test2 = u"äöüß %s"
print "ohne:", test2
print "ohne:", test2 % test
try:
    print "mit:", test2.encode(OUTCODING) % test
except Exception, e:
    print "Fehler:", e

try:
    print "mit:", test2.encode(OUTCODING) % test.encode(OUTCODING)
except Exception, e:
    print "Fehler:", e


print "-"*70

l = os.listdir(".")
print "ohne:",
try:
    for i in l: print i,
except Exception, e:
    print "Fehler:", e

print "\nmit:",
try:
    for i in l: print i.encode(OUTCODING),
except Exception, e:
    print "Fehler:", e
Im Verz. liegt eine Datei mit Sonderzeichen und da ist das Problem. Diese bekomme ich nie richtig Angezeigt. Hier die Ausgaben:
outencoding: cp850

ohne: testäöüß
mit: testäöüß
----------------------------------------------------------------------
ohne: äöüß %s
ohne: äöüß testäöüß
mit: Fehler: 'ascii' codec can't decode byte 0x84 in position 0: ordinal not in range(128)
mit: äöüß testäöüß
----------------------------------------------------------------------
ohne: leer õ÷³▀ leer õ÷³▀.txt test.py
mit: Fehler: 'ascii' codec can't decode byte 0xe4 in position 5: ordinal not in range(128)
Festhalten kann man eigentlich, das man ohne Encoding besser da steht... Nur, wie bekomme ich Dateinamen mit Sonderzeichen richtig dargestellt???

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Freitag 20. Januar 2006, 09:17

jens hat geschrieben:Im Verz. liegt eine Datei mit Sonderzeichen und da ist das Problem. Diese bekomme ich nie richtig Angezeigt. Hier die Ausgaben:
Hi Jens!

Du musst, wenn du Daten von Außen erhälst, diese zuerst ins Unicode umwandeln.

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: UTF-8 -*-

import sys, os

OUTCODING = sys.stdout.encoding or sys.getfilesystemencoding()
FSE = sys.getfilesystemencoding()

print "outencoding:", OUTCODING
print

test = u"testäöüß"
print "ohne:", test
print "mit:", test.encode(OUTCODING)

print "-"*70

test2 = u"äöüß %s"
print "ohne:", test2
print "ohne:", test2 % test
try:
    print "mit:", (test2 % test).encode(OUTCODING)
except Exception, e:
    print "Fehler:", e

try:
    print "mit:", test2.encode(OUTCODING) % test.encode(OUTCODING)
except Exception, e:
    print "Fehler:", e

print "-"*70

l = os.listdir(".")
print "ohne:",
try:
    for i in l: 
        print i,
except Exception, e:
    print "Fehler:", e

print "\nmit:",
try:
    for i in l: 
        print i.decode(FSE).encode(OUTCODING),
except Exception, e:
    print "Fehler:", e
lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
jens
Moderator
Beiträge: 8482
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Freitag 20. Januar 2006, 19:17

Hm! OK, aber eigentlich müßte ich nur die Dateinamen überhaupt behandeln, denn alles andere klappt ja eh schon von alleine :)

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Freitag 20. Januar 2006, 19:34

jens hat geschrieben:Hm! OK, aber eigentlich müßte ich nur die Dateinamen überhaupt behandeln, denn alles andere klappt ja eh schon von alleine :)
Hi Jens!

Das ist es ja, was nicht stimmt. Probier dein Skript unter Linux mit UTF-8 als Standard und mit Linux mit iso-8859-1 als Standard aus. Dann noch mit Windows. Spätestens unter Windows wird das Skript bei Zeile (lass mich mal nachsehen...) 13 einen Fehler werfen, da du versuchst, Unicode-Zeichen in eine Konsole zu schreiben, die nichts damit anfangen kann.

Wenn du dich aber immer darum kümmerst, dass alles was du von der Konsole bekommst, nach Unicode umwandelst und alles was auf die Konsole geschrieben wird, in das Coding der Konsole umgewandelt wird, dann ist es egal, welches Coding die Konsole verwendet.

Das Coding der Konsole bekommst du mit "sys.stdout.encoding" raus.

Unabhängig vom Coding der Konsole gibt es noch das Coding, in dem die Dateinamen gespeichert werden. Dieses Coding bekommst du mit "sys.getfilesystemencoding()" heraus.

Da man in manchen IDEs, beim Ausführen nicht auf "sys.stdout.encoding" zugreifen kann oder einfach nur nichts dabei raus kommt, nehme ich als Alternative noch "sys.getfilesystemencoding()" mit rein. Das klappt bei mir recht gut.

OUTCODING = sys.stdout.encoding or sys.getfilesystemencoding()
FSE = sys.getfilesystemencoding()

Jetzt fällt mir nichts mehr ein. Muss wohl ein kleines Blackout sein. :roll:

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Antworten