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.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@kodela:
Für deutsche Windowsinstallation nehmen Editoren idR cp1252 (Windows-1252) als Voreinstellung. Heisst wenn Du einen Editor aufmachst und nicht dessen Voreinstellung dauerhaft umgestellt hast, sollte er Dateien mit cp1252 kodieren. Dann MUSS der "coding"-Kommentar darauf zeigen, sonst sieht Python da alles mögliche nur nicht Deine Umlaute. Damit hättest Du das Editor-Encoding --> Pythonsource-Encoding Problem gelöst.

Für das Output-Encoding musst Du das ggf. separat selbst lösen:

Bytestrings sollte man zunächst in unicode überführen (generell immer eine gute Idee, da man pythonintern viel besser mit Unicode hantieren kann):

Code: Alles auswählen

'äöüß'.decode('cp1252')
oder bei literaler Eingabe gleich das u'' voranstellen:

Code: Alles auswählen

# coding: cp1252

u'äöüß'
# ist in Python 2.x  äquivalent zu
'äöüß'.decode('cp1252')
Beim eigentlichen Print-Output kann es passieren, dass das Python entweder das Encoding nicht erkannt hat (zu prüfen mit `sys.stdout.encoding`), ein falsches gesetzt ist oder das unterstützte Encoding bestimmte Zeichen nicht beherrscht. Letzteres führt zum `UnicodeEncodeError`, da hilft nur entweder die Zeichen zu ersetzen/verwerfen (siehe https://docs.python.org/2/howto/unicode ... icode-type) oder wenn man Glück hat, unterstützt das Device irgendein Unicode-Encoding. Dann nimmt man dieses für den Output:

Code: Alles auswählen

print u'äöü߀'.encode('utf-??')
Die Window-Konsole kann prinziell Unicode, muss dafür aber explizit umgestellt werden (für höhere Unicode-Zeichen muss dann zusätzlich noch eine Unicode-Schrift eingestellt sein, sonst fehlen die Glyphen).
kodela
User
Beiträge: 185
Registriert: Montag 12. Oktober 2015, 21:24
Wohnort: Landsberg am Lech
Kontaktdaten:

Hallo @jerch:

Danke für Deine Hinweise. Leider bringen auch die mich nicht weiter.

Für den Editor der NetBeans-IDE ist Windows-1252 defaultmäßig für das Encoding eingesetzt und das belasse ich auch so. Da Durch meine vielen Testläufe ja einiges durcheinander gekommen sein könnte, habe ich den Text (zum wiederholten Male) neu eingetippt. Für den Coding-Kommentar habe ich ebenfalls cp1252, das ja Windows 1552 entspricht, eingestellt. Mit der Darstellung im Editor gibt es damit keinerlei Probleme.

Die beiden von Dir vorgeschlagenen Varianten der Überführung des Bytestring nach unicode funktionieren bei mir leider nicht. Für

teststring = u'Wer Öl für ein großes Übel hält, bekommt bösen Ärger' (Zeile 6)

bekomme ich folgende Fehlermeldung:

Code: Alles auswählen

Traceback (most recent call last):
  File "D:\Python\Projekte\Testprojekt\src\testprojekt.py", line 13, in <module>
    main()
  File "D:\Python\Projekte\Testprojekt\src\testprojekt.py", line 9, in main
    print teststring
UnicodeEncodeError: 'ascii' codec can't encode character u'\xd6' in position 4: ordinal not in range(128)
In der Zeile 9 steht die print-Ausgabe (print teststring)

Exakt die selbe Fehlermeldung bekomme ich bei einer Transkodierung mit

teststring = 'Wer Öl für ein großes Übel hält, bekommt bösen Ärger'.decode('cp1252') (Zeile 6)

Frage ich anschließend mit sys.stdout.encoding das Encoding ab, bekomme ich als Ergebnis None.

Wenn ich diese Fehlermeldungen ignoriere und den Code über die Konsole ausgebe, werden die Zeichen korrekt dargestellt. Damit kann man leben. Nochmals vielen Dank für Deine Hinweise.

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

@kodela:
Probier mal in der Konsole:

Code: Alles auswählen

#> chcp 1252
#> python <dein programm>
Mit

Code: Alles auswählen

import sys
sys.setdefaultencoding('cp-1252')
kannst Du dann noch versuchen, Python das Encoding für STDOUT klar zu machen. Dein UnicodeEncodeError deutet darauf hin, dass print auf ASCII zurückfällt, weil es das Encoding nicht hat. Und Ö ist nicht im ASCII-Bereich, sondern 0xD6 sowohl in cp1252 als auch in Unicode.
kodela
User
Beiträge: 185
Registriert: Montag 12. Oktober 2015, 21:24
Wohnort: Landsberg am Lech
Kontaktdaten:

Hallo @jerch:

das habe ich gemacht:

Code: Alles auswählen

D:\Python\Projekte\Testprojekt\src>chcp 1252
Aktive Codepage: 1252.

D:\Python\Projekte\Testprojekt\src>python
Python 2.7.6 (default, Oct 21 2015, 09:27:24) [MSC v.1500 32 bit (Intel)] on win
32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.setdefaultencoding('cp-1252')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'setdefaultencoding'
>>>
und das ist das Ergebnis:

Code: Alles auswählen

Wer Íl f³r ein gro▀es ▄bel hõlt, bekommt b÷sen ─rger
Trotzdem herzlichen Dank

MfG, kodela
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

Was den AttributeError betrifft, ist die Dokumentation ist da ziemlich klar:

sys.setdefaultencoding(name)

Set the current default string encoding used by the Unicode implementation. If name does not match any available encoding, LookupError is raised. This function is only intended to be used by the site module implementation and, where needed, by sitecustomize. Once used by the site module, it is removed from the sys module’s namespace.
In specifications, Murphy's Law supersedes Ohm's.
kodela
User
Beiträge: 185
Registriert: Montag 12. Oktober 2015, 21:24
Wohnort: Landsberg am Lech
Kontaktdaten:

Hallo allen,

die Ursache ist gefunden und das Problem behoben.

Aus welchen Gründen auch immer war bei mir die Codepage 850 eingestellt. Für die Darstellung der Sonderzeichen sollte aber die Codepage 1252 eingestellt sein.

Die Umstellung von der Standard-Codepage 850 erfolgt in der Registry unter

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage

Dort ist der Eintrag für den Wert OEMCP von 850 auf 1252 zu ändern. Die Änderung wird erst nach einem Neustart wirksam.

Ich bedanke mich bei allen, die mir bei der Problemsuche behilflich waren, sehr herzlich.

MfG, kodela
bb1898
User
Beiträge: 200
Registriert: Mittwoch 12. Juli 2006, 14:28

kodela hat geschrieben: Aus welchen Gründen auch immer war bei mir die Codepage 850 eingestellt.
Dass das unter Windows das Normale ist, hat Dir Sirius3 schon im ersten Beitrag auf dieser Seite gesagt. Es scheint nur auch bei den Antwortenden unter den Tisch gefallen zu sein.
Für die Darstellung der Sonderzeichen sollte aber die Codepage 1252 eingestellt sein.
Nein, cp850 kann Umlaute genauso, man muss Python nur sagen, dass die Ausgabe so erfolgen soll. Also (ungetestet mangels Python 2):

Code: Alles auswählen

teststring = u"äüöß"
print teststring.encode('cp850')
Die Umstellung von der Standard-Codepage 850 erfolgt in der Registry unter

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage

Dort ist der Eintrag für den Wert OEMCP von 850 auf 1252 zu ändern. Die Änderung wird erst nach einem Neustart wirksam.
Nicht nötig. Hilfreicher ist ein Umsteigen auf Python 3. Das schreibt Dir mit "print(teststring)" den String mit korrekten Umlauten in die Windows-Konsole, ohne dass Du irgendwo hin- oder hercodierst.
BlackJack

@bb1898: Was macht Python 3 denn anders als Python 2 wenn man dort eine Unicode-Zeichenkette ausgibt? Auch Python 2 kodiert das automagisch.

Edit: Python-Quelltext:

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf8

print u'Noch mehr Öl ins Feuer. :-)'
Ausgabe:

Code: Alles auswählen

H:\>python forum4.py
Noch mehr Öl ins Feuer. :-)
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@bb1898:
Das Problem im Threadverlauf war, dass kodelas Dateiencoding unklar war bzw. nicht stimmen konnte. Warum er die Konsolenausgabe jetzt per Umstellung auf cp-1252 "gelöst" hat - kA. Solange Python die richtigen Encodings von Datei bis Ausgabe hat, sollte das auch unter 2.x klappen.
kodela
User
Beiträge: 185
Registriert: Montag 12. Oktober 2015, 21:24
Wohnort: Landsberg am Lech
Kontaktdaten:

Hallo @bb1898:

Danke für Deine Hinweise. Besonders neu sind sie allerdings nicht. Dass bei Windows Vista und 7 die Codepage 850 ein quasi Standard ist, hat nicht nur Sirius3 festgestellt, auch ich habe geschrieben, dass die Umstellung von der Standard-Codepage 850 in der Registry erfolge.

Standard ist aber eine Sache, die Realität eine andere. Wenn man zum Beispiel unter Google den Suchbegriff "standard für windows codepage" eingibt, bekommt man an erster Stelle diesen Verweis: Windows-1252 - Wikipedia. Auch bei den nachfolgenden Verweisen findet man noch lange keine Hinweise auf die Codepage 850.

Nach meinen Erfahrungen werden im deutschen Sprachraum Computer mit vorinstalliertem Windows in den allermeisten Fällen mit der Codepage Windows-1252 ausgeliefert. Auf zwei anderen Rechnern von mir ist diese Codepage zum Beispiel eingestellt, ohne dass ich dies explizit gemacht hätte.

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.

Neu ist also lediglich Dein Vorschlag, von Python 2 auf Python 3 umzusteigen. Nun, wegen einem Miniproblem, das sich durch eine simple Änderung in der Registry beheben lässt, auf Python 3 umzusteigen, nein, das sehe ich nicht als einen guten Vorschlag an.

MfG, kodela
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: 17750
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: 17750
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