Encoding-Namen und ihre Kurzformen...

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
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Hallo,

weiß jemand, woher die Encoding-Namen und ihre Aliase (was für ein Wort... :shock: ) in Python stammen?

Mir geht es darum, ob Vergleiche wie

Code: Alles auswählen

>>> sys.stdout.encoding == 'UTF-8'
auch mal in die Hose gehen können, wenn dort statt 'UTF-8' vielleicht auch mal ein 'UTF8' stehen könnte...?
Bei 'ISO-8859-1' ist das ja noch verworrener, kann ich ja als Parameter sowohl 'iso8859', 'latin1', 'iso-8859-1' ... angeben.

Wird also bei Rückgaben von encoding-Namen immer die gesamte Form ('UTF-8', 'ISO-8859-1', 'CP-1252') verwendet (die ich so weder im Python '/encodings'-Verzeichnis noch in der dortigen 'aliases.py' finden konnte)?

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
problembär

Erster Gedanke war, man könnte vielleicht folgendes machen:

Code: Alles auswählen

if sys.stdout.encoding in ('ISO-8859-1', 'iso-8859-1', 'iso8859', 'latin1'):
    pass
;)
Andev
User
Beiträge: 24
Registriert: Dienstag 17. Januar 2012, 15:55

Hallo,

üblicherweise wird der Codec-Name zurückgegeben, darauf verlassen würde ich mich aber nicht, nicht zuletzt da der encoding-Wert beliebig verändert werden kann. Eine einfache Methode zum Überprüfen ist mir nicht bekannt, vielleicht kennt die ja jemand anders.
Eines aber: Der Bindestrich '-' wird automatisch als Alias für '_' gewertet. 'utf-8' ist also nichts anders als ein Alias für 'utf_8' und wird nicht explizit in den Tabellen aufgelistet.
lunar

@mutetella: Über das "codecs" Modul erhältst Du den kanonischen Namen einer Textkodierung:

Code: Alles auswählen

In [4]: codecs.lookup('iso8859-1').name
Out[4]: 'iso8859-1'

In [5]: codecs.lookup('iso 8859-1').name
Out[5]: 'iso8859-1'

In [6]: codecs.lookup('latin1').name
Out[6]: 'iso8859-1'

In [7]: codecs.lookup('ISO 8859-1').name
Out[7]: 'iso8859-1'

In [8]: codecs.lookup('utf-8').name
Out[8]: 'utf-8'

In [9]: codecs.lookup('utf8').name
Out[9]: 'utf-8'
Auf den exakten kanonischen Namen würde ich mich nicht verlassen, aber Du kannst das "CodecInfo"-Objekt für einen bekannten Codec holen, und dessen Name dann mit dem CodecInfo-Objekt für die zu prüfende Kodierung vergleichen, beispielsweise "codecs.lookup(sys.stdout.encoding).name == codecs.lookup('utf-8').name".

Ich sehe allerdings gerade nicht, wozu man sowas brauchen könnte...
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

lunar hat geschrieben:Ich sehe allerdings gerade nicht, wozu man sowas brauchen könnte...
Wenn ich einen Tastendruck vom Terminal einlese, hängt es vom encoding des Terminals ab, ob ich z. B. für das 'ä' ein '\xe4' (LATIN1) oder ein '\xc3\xa4' erhalte. Wenn ich die Bytes dann übersetze kann das '\xe4' als Start einer 3-byte Sequenz (UTF-8) oder als 'ä' (LATIN1) interpretiert werden, das '\xc3' als Start einer 2-byte Sequenz (UTF-8) oder als 'Ã' (LATIN1).
Jetzt könnte man natürlich die Sequenzen anhand der folgenden Bytes, die zwischen '\x80' und '\xbf' liegen müssen, identifizieren.
Könnte man... wenn allerdings das encoding feststeht, kann ich bei ISO's (und anderen encodings, die 'nur' mit 1 Byte auskommen) die Sequenzerkennung und -übersetzung überspringen und das Byte gleich weiterverwenden.

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
lunar

@mutetella: Ich sehe immer noch nicht, warum man da jetzt die Kodierung prüfen sollte. Du kannst doch einfach alle Bytes lesen und dann einfach mit der Kodierung dekodieren. Ich glaube, Du versuchst hier wieder mal ein XY-Problem zu lösen...
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Ein Bytestring vom System kann doch einfach mit decode() in einen richtigen (Unicode) String konvertiert werden. Ohne Argument benutzt decode() das Encoding des Systems. Da muss man doch nicht mit hart-verdrahteten Namen arbeiten?!

Stefan
BlackJack

@sma: Ohne Argument benutzt `decode()` bei mir ASCII und nicht die Kodierung des Systems. So eine Kodierung gibt es ja auch gar nicht.

Code: Alles auswählen

In [55]: 'hällö'.decode()
---------------------------------------------------------------------------
UnicodeDecodeError                        Traceback (most recent call last)

/home/bj/<ipython console> in <module>()

UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 1: ordinal not in range(128)
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@sma + lunar:
Grundsätzlich ja, wenn die Umgebung 'sauber' ist. Das von mir beschriebene Szenario tritt dann auf, wenn das Terminal ein anderes encoding als das Systemencoding verwendet, z. B. ein xterm, das mit der Option '-en iso88591' aus einer 'utf-8'-Umgebung heraus gestartet wird. Wenn ich hier 'sys.stdout.encoding' abfrage, erhalte ich 'UTF-8', das ausgelesene/die ausgelesenen Byte(s) müssen allerdings 'iso8859-1'-decodiert werden.

Das Problem lässt sich am einfachsten umgehen, wenn ich nicht 'sys.stdout.encoding' sondern das jeweilige encoding des Terminals abfrage. Eine Möglichkeit, an diese Information zu kommen, suche ich gerade (bin da für Hinweise sehr empfänglich... ;-) ).

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Wenn sys.stdout.encoding nicht dem Encoding des Terminals entspricht, hat entweder deine Python Implementation einen Bug, das Terminal einen Bug oder das System ist falsch konfiguriert. Irgendwelche abenteuerlichen Workarounds die wahrscheinlich ohnehin nicht wirklich funktionieren dürften da wohl kaum eine adequate Lösung sein.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@DasIch:
Ganz so einfach ist es leider nicht... ein zerschossenes System oder ein Bug wäre mir natürlich auch am liebsten... ;-)

Python übernimmt das encoding aus 'LANG'. Und 'LANG' gibt keine Auskunft darüber, welches encoding im jeweiligen Terminal gerade verwendet wird.
Anderst herum: Wenn ich in 'LANG' ein zum laufenden Terminal differentes encoding hinterlege, erhalte ich über 'sys.stdout.encoding' das encoding aus 'LANG', nicht das des Terminals.

Und dass ein Terminal auch mal unter einem anderen encoding als dem des Systems läuft ist ja keine an den Haaren herbeigezogene Möglichkeit, oder?

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
deets

@mutetella

Ja, natuerlich kann ich das aendern. Jederzeit. Auch wenn du gerade Ausgaben in UTF-8 machst in einer Schleife, vor der du das encoding umgestellt hast.

Mit anderen Worten: es gibt keinen 100%igen Weg. Wenn der User das encoding des Terminals zwischendurch umstellt (das Terminal selbst sollte ja die LANG-variable setzten zu Beginn der Session, wenn du die nicht selbst manipulierst) - dann ist halt Essig.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

mutetella hat geschrieben:Python übernimmt das encoding aus 'LANG'. Und 'LANG' gibt keine Auskunft darüber, welches encoding im jeweiligen Terminal gerade verwendet wird.
Anderst herum: Wenn ich in 'LANG' ein zum laufenden Terminal differentes encoding hinterlege, erhalte ich über 'sys.stdout.encoding' das encoding aus 'LANG', nicht das des Terminals.
Diese sollten möglichst identisch sein, sind sie i.d.R. auch schliesslich verlässt sich jedes lokalisierte Program darauf.
Und dass ein Terminal auch mal unter einem anderen encoding als dem des Systems läuft ist ja keine an den Haaren herbeigezogene Möglichkeit, oder?
Diese Möglichkeit könnte durchaus eintreten aber im Normalfall sollte sie es nicht. Selbst wenn sie eintritt wird es deswegen nicht automatisch dein Problem, speziell dann wenn du das Problem ohnehin nicht lösen kannst, es sei den du errätst zufällig die Lösung.
lunar

@mutetella: Es ist ein Bedienungsfehler des Nutzers, wenn Lokalisierungseinstellungen und Terminalkodierung nicht zusammen passen. Wenn Du in einer UTF-8-Umgebung die Terminal-Kodierung auf ISO 8859-1 umstellst, dann funktioniert kein Programm mehr korrekt.

Sowas wie die "Terminal-Kodierung" gibt es nicht in standardisierter Weise und mithin kann ein Programm sie auch nicht einfach so abfragen. Nutze "$LANG" beziehungsweise "sys.stdout.encoding", "sys.getfilesystemencoding()" und Konsorten. Wenn der Benutzer die Kodierungseinstellungen verhaut, ist das nicht Deine Schuld und im Programm Du kannst auch nichts dagegen tun.

@deets: Ich kenne kein Terminalemulator unter Linux, welcher automatisch "LANG" setzt. Der Nutzer muss schon selbst dafür sorgen, dass die Lokalisierungs- und Kodierungseinstellungen alle zusammen passen.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Ok, letztlich hab' ich ja immer noch die Möglichkeit, ein 'set_encoding()' oder sowas einzubauen, über das der Nutzer bei Bedarf das encoding ändern kann, falls Terminal und System variieren.
Mir hätte hier ein Automatismus gefallen, so eine Art 'SIGENCCH'...

Und dass andere Konsolenprogramme auch Schwierigkeiten in der Übersetzung außerhalb des Systemencodings haben versöhnt mich ein wenig, unbefriedigend bleibt es trotzdem... :(

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
lunar

@mutetella: Mein Gott, wie oft kommt sowas denn schon vor? Ich meine, wer kommt denn schon auf die Idee, ein Terminal absichtlich und wissentlich falsch zu konfigurieren?

Und ja, Terminualemulator sind unbefriedigend... aber eben auch schon steinalt, und vor 40 Jahren waren Textkodierung noch ein ziemlich überschaubares Thema.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@lunar: Beim gnome-terminal kann ich mit 3 Klicks eine andere Zeichenkodierung einstellen. Jedem anderen mir bekannten Terminal kann ich über eine Option die Kodierung mitgeben.
Ich würde also nicht von einem 'absichtlich und wissentlich falsch' konfiguriertem Terminal sondern von einem Feature sprechen, das (x)terms nunmal bieten und von den darin laufenden Programmen auch berücksichtigt werden sollte.

Und ich vermute mal, dass das Problem weniger von den Terminals als vielmehr von der Unmöglichkeit, stdout/stdin zu separieren, verursacht wird. Aber diese Vermutung kann auch ein zum Himmel stinkender Blödsinn sein, das weiß ich nicht... :K

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
BlackJack

@mutetella: Programme können die Kodierung des Terminals aber nicht berücksichtigen, da es ja wohl keinen standardisierten Weg gibt, an diese Information heran zu kommen.

Die Einstellungsmöglichkeit in Terminals ist für Programme gedacht, die sich nicht um LANG oder LC_LANG kümmern und einfach Stur mit ihrer fest eingebauten Kodierung operieren. Wenn man daran rum schraubt ohne dass man so ein Programm starten will und LANG/LC_ALL nicht auch passend setzt, dann konfiguriert man das Terminal absichtlich falsch! Vielleicht unwissentlich, aber falsch bleibt es trotzdem.
lunar

@mutetella: Es gibt ja auch triftige Gründe, die Kodierung eines Terminals zu ändern. Beispielsweise bei einer SSH-Verbindung zu einem Server, bei dem eine andere Kodierung in $LANG eingestellt ist. Oder bei einer seriellen Verbindung zu einem embedded-System, dass eine hart kodierte Text-Kodierung verwendet.

Wenn man allerdings die Kodierung für die lokale Shell verändert, ohne deren Lokalisierungseinstellungen anzupassen, dann konfiguriert man das Terminal falsch. Und da man kaum aus Versehen im Kodierungsdialog des Terminals landet, geschieht das auch wissentlich und absichtlich. Klar kann das mal passieren, wenn man beispielsweise nach dem Schließen der SSH-Verbindung vergisst, die Kodierung zurückzusetzen, aber dann man selbst Schuld. Nicht das Programm, welches dann merkwürdige Zeichen anzeigt...

Schuld ist das Programm aber, wenn es merkwürdige Zeichen anzeigt, weil es versucht, schlauer zu sein als der Nutzer und die Text-Kodierung auf magische Weise erraten will.
Antworten