Darstellung deutscher Sonderzeichen 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.
BlackJack

@kodela: Die Konsole verwendet in der Regel nicht die Standard-*Windows*-Codepage sondern die Standard-*DOS*-Codepage für die jeweilige Region die im System eingestellt ist. Und cp850 ist für Deutschland die übliche DOS-Codepage. Macht ja auch Sinn, denn diese Konsole ist ja ein Überbleibsel aus DOS-Zeiten und ermöglicht(e) die Ausführung von DOS-Programmen und die gehen in der Regel von der DOS-Codepage aus.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

kodela hat geschrieben:Auch die beiden von Dir vorgeschlagenen Varianten, den Ausgabestring entweder mit encode('cp850') oder dem vorangestelltem Literal "u" an die Einstellung unter Windows anzupassen, wurden hier bereits angesprochen und als gangbare Wege festgestellt. Nur ist es mir aber lieber, wenn ein Programm nicht ganz gezielt an eine Umgebung angepasst, sondern so gestaltet ist, dass es nach Möglichkeit unter allen Umgebungen funktioniert.
Kleine Anmerkung dazu - wenn Du es plattform unabhängig halten willst, fährst Du mit der Kombination aus richtigem Coding-Kommentar + u''-Strings unter Python 2.x am besten. Dann transkodiert Python beim Laden des Sourcescodes literale Strings automagisch zu Unicode, womit sich in 95% der Fälle eh besser arbeiten lässt. (Ist ein Grund, warum in Python 3 literale Strings nicht mehr als Bytestrings verarbeitet werden.)
kodela
User
Beiträge: 185
Registriert: Montag 12. Oktober 2015, 21:24
Wohnort: Landsberg am Lech
Kontaktdaten:

Hallo @jerch:

Danke für den Hinweis. Ja Du hast vermutlich Recht. Man könnte für die Ausgabe bestimmte Strings auch noch nach Unicode transcodieren.

MfG, kodela
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@kodela:
Der interne Unicodetyp von Python ist nicht für die direkte (Ein-) Ausgabe gedacht, er hat nicht einmal eine einheitliche Byte-Repräsentation (kann 2 oder 4 Bytes lang sein, je nach OS und Pythonversion). Der Unicodetyp ist für die interne Verarbeitung optimiert, für IO mit dem Betriebssystem muss eigentlich immer transkodiert werden (Dekodierung zu Unicode bei Eingabe, Enkodierung von Unicode zu Zielkodierung bei Ausgabe):

Eingabe --> Dekodierung - Unicode - Kodierung --> Ausgabe

Python versucht nun dieses umständliche Hin- und Herkodieren etwas zu verstecken. So macht der Interpreter z.B. Annahmen über die Kodierung von Standard-IO-Kanälen wie STDIN und STDOUT. Sind diese Annahmen richtig und alle Zeichen im Ausgabe-Encoding darstellbar, kann man z.B. am Interpreter-Prompt eines Terminals einen Unicodestring direkt ausgeben lassen. Python kodiert dabei den Unicodestring im Hintergrund ins Zielformat. Eine Eingabe am Prompt verläuft umgekehrt. Analog wird in Quelldateien ein literaler Unicodestring entsprechend des coding-Kommentars dekodiert.
kodela hat geschrieben:Man könnte für die Ausgabe bestimmte Strings auch noch nach Unicode transcodieren.
Lange Rede kurzer Sinn - solange Python mit seiner Annahme über die korrekte Ausgabe-Kodierung besser Bescheid weiss als Du, stimmt das. Ansonsten nicht.
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

Um hier mal den Wildwuchs an falschen Tipps und herumgerate einzudämmen ein paar Fakten:
1. Python kann auf Konsolen Unicode-Strings im richtigen Encoding ausgeben, egal ob Python 2 oder 3. Da braucht man nichts in seiner Registry herumzuspielen oder von Hand irgendwelche Encoding-Magie anwenden. Python weiß normalerweise besser, welches Encoding zu benutzen ist, als irgendein User.
2. das verwendete Encoding steht in sys.stdout.encoding. Wer mit sys.getdefaultencoding oder sys.setdefaultencoding herumspielt macht definitiv etwas falsch.
3. Python 2 kann neben Unicodestrings auch Byte-Strings ausgeben, dann ohne Gewähr, dass das Encoding stimmt. Bei Python3 ist man dem eingestellten Encoding ausgeliefert.
3. Jetzt wird es kompliziert: Bei Dateiumleitungen verhalten sich Python2 und Python3 unterschiedlich: Python2 setzt sys.stdout.encoding auf None, so dass man nur noch ByteStrings oder ASCII ausgeben kann. Python3 rät irgendein Encoding, das es dann benutzt. In Python2 ist es also ganz einfach, eine Dateiumleitung zu erkennen und dann ein gewünschtes Encoding einzustellen:

Code: Alles auswählen

import sys
import codecs

if sys.stdout.encoding is None:
    sys.stdout = codecs.getwriter('utf8')(sys.stdout)

print u"Tätüt trarö"
Will man das Python3-Verhalten möglichst exakt nachbilden, bietet sich diese Lösung an:

Code: Alles auswählen

import sys
import codecs
import locale

if sys.stdout.encoding is None:
    sys.stdout = codecs.getwriter(locale.getpreferredencoding() or 'utf8')(sys.stdout)
mit dem Nachteil, dass, wenn man tatsächlich in eine Datei umleitet, sich das Encoding je nach Systemeinstellung ändern kann.
kodela
User
Beiträge: 185
Registriert: Montag 12. Oktober 2015, 21:24
Wohnort: Landsberg am Lech
Kontaktdaten:

Hallo @Sirius3,

In keiner Weise bezweifle ich Deine Aussage. Python kann auf Konsolen Unicode-Strings im richtigen Encoding ausgeben, egal ob Python 2 oder 3. Das ist aber nur die eine Seite der Medaille.

Ich arbeite unter NetBeans, worauf ich hingewiesen habe. Unter der IDE von NetBeans, die mir durch meine jahrelange Arbeit mit Java vertraut ist, kann ich auch Python-Skripte debuggen. Die Ausgabe erfolgt ebenfalls über ein eigenes Fenster der IDE. Unter Netbeans kann ich für jedes Projekt die für das Abspeichern zu verwendende Codepages einstellen. Zur Auswahl stehen 169 Codepages. Die Voreinstellung ist Windows 1252.

In dieser Umgebung wurden Sonderzeichen im Ausgabefenster der IDE richtig angezeigt. Wurde ein Skript jedoch in der Konsole aufgerufen, stimmten die Sonderzeichen nicht mehr.

Bevor ich mich mit der Bitte um Hilfe an das Forum wandte, habe ich selbst versucht, das Problem in den Griff zu bekommen und habe dafür auch von NetBeans die Codepages UINT8, UINT16, IBM850 durchprobiert, leider erfolglos. Es gelang mir nicht, Sonderzeichen von der IDE und der Konsole richtig dargestellt zu bekommen.

Auch die vielen Antworten, die ich auf meine Anfrage bekam, eröffneten mir zwar teilweise neue Perspektiven, aber keine Lösung meines Problems und so suchte ich weiter und fand im Netz mehrfach einen Hinweis auf die Möglichkeit, die Codepage für das System umzustellen.

Ich denke, das war weder eine "Herumspielerei" in meiner Registry und noch hatte es etwas mit der Anwendung irgendwelcher "Encoding-Magie" zu tun.

Heute habe ich auf Grund Deines letzten Beitrages in stundenlanger Arbeit (in Deinen Augen vielleicht Spielerei) noch einmal versucht, die korrekte Ausgabe der Sonderzeichen unter der standardmäßigen Codepage 850 und unter NetBeans zu erreichen, leider vergeblich. Ich bin deshalb wieder zur Codepage 1252 zurück gekommen. Das ist für mich die Lösung des Problems.

MfG, kodela
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@kodela:
Was gibt denn NetBeans aus, wenn Du einfach alles als Unicodestrings vorhältst? Evtl. ist diese Ausgabe eine simple Pipe ohne Terminalmagie, dann fehlt Python das Wissen über dessen korrekte Kodierung. Daher kommt dann auch der ASCII-Error. Um das zu beheben, müsste man erstmal klären, was die Ausgabe in NetBeans als Encoding alles akzeptiert.

@Sirius3:
Dieses "Herumgerate" ist der Versuch nachzuvollziehen, was da wie eingstellt ist bzw. Probleme macht.
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

@kodela: Dein Problem war/ist ja, dass das Encoding der Python-Datei nicht mit dem angegebenen in der ersten Zeile übereinstimmt. Das ist ein Problem des Editors. Ich benutze kein NetBeans, aber vielleicht solltest Du mal in einem anderen Editor prüfen, ob Dein vermutetes Encoding mit dem tatsächlichen übereinstimmt. Wie schon mehrfach geschrieben, ist, solange Du konsequent auf Unicode-Strings setzt, ein Fehler durch Ausgabeencodierung gering, ein Fehler der Dateiencodierung viel wahrscheinlicher.
kodela
User
Beiträge: 185
Registriert: Montag 12. Oktober 2015, 21:24
Wohnort: Landsberg am Lech
Kontaktdaten:

Hallo @Sirius3:

ich habe den Skriptext über Notebook und Notepad++ abgespeichert und die Ergebnisse mit dem Skript, so wie es NetBeans abspeichert, mit einem Hexeditor verglichen. Das Ergebnis von Notepad war mit dem Skript identisch. Jedes Zeichen war durch ein Byte codiert. Beim Ergebnis von Notepad++ waren die sieben Sonderzeichen durch jeweils zwei Byte codiert. Das bedeutet, dass Notepad++ den Text als Unicode speichert. Der Standard-Editor und auch Netbeans (mit der Einstellung Windows-1252) speichern dagegen in ANSI-Codierung (Windows 1252) ab.

Mit NetBeans könnte ich jetzt zwar auch für die Speicherung UTF8 einstellen, bekomme aber dann für die Anzeige in der IDE nur diese kryptische Ausgabe der Sonderzeichen, was mir nicht gefällt. Interessant ist auch, dass die beiden unterschiedlich abgespeicherten Texte von allen drei Editoren richtig dargestellt werden.

Wie ich bereits geschrieben habe, werde ich bei mir die Codepage Windows 1252 lassen. Diese ist übrigens auf zwei anderen Rechnern von mir ebenfalls eingestellt, ohne dass ich hier Hand angelegt hätte. Die Skripte werden damit so abgespeichert, wie es der simple Notepad-Editor auch machen würde und das kann ja nicht so falsch sein.

Ich denke übrigens, die Sache ist ausdiskutiert und irgend welche neuen Gedanken zu diesem Thema nicht mehr zu erwarten. Für die sehr rege Beteiligung aller hier Mitwirkenden bedanke ich mich.

MfG, kodela
Antworten