UTF-8-Konsole Windows

Probleme bei der Installation?
Hellstorm
User
Beiträge: 231
Registriert: Samstag 22. Juni 2013, 15:01

Hallo,

hat jemand einen Tipp, wie man vernünftigen Unicode-Support unter Windows (7) hinbekommt? Die normale cmd.exe kann man ja wirklich vergessen, deswegen habe ich mir jetzt ConEmuheruntergeladen. Das scheint mir besser zu sein und ist schon mal halbwegs konfigurierbar.

Als einfachen Test möchte ich einfach etwas Japanisches angezeigt bekommen. Die ganz einfache Python-3-Datei ist daher:

Code: Alles auswählen

print("日本語")
ConEmu zeigt mir (im Gegensatz zur cmd.exe) auf jeden Fall schon einmal Japanisch an. Dateinamen auf Japanisch gehen, ich kann auch Verzeichnisse auf Japanisch erstellen, Japanisch eintippen usw.

Wenn ich jetzt allerdings die Datei ausführe, kommt folgende Fehlermeldung:

Code: Alles auswählen

PS D:\> python test.py
Traceback (most recent call last):
  File "test.py", line 1, in <module>
    \ufeffprint("\u65e5\u672c\u8a9e")
  File "C:\Programmieren\Python33\lib\encodings\cp850.py", line 19, in encode
    return codecs.charmap_encode(input,self.errors,encoding_map)[0]
UnicodeEncodeError: 'charmap' codec can't encode characters in position 0-2: character maps to <undefined>
Ich glaube nicht, dass der Fehler an der Konsole liegt, da diese normalen japanischen Text verarbeitet. Es scheint mir eher an Python zu liegen.

Hat da jemand ein Tipp? Unter Linux klappt das alles ohne Probleme, aber unter Windows irgendwie nur sehr begrenzt.

Danke :)
BlackJack

@Hellstorm: Letztendlich darf man keine Unicode-Zeichenketten mit ``print`` ausgeben. Das funktioniert auch unter Linux nicht. Leite dort die Ausgabe die problemlos auf dem Terminal angezeigt werden kann in eine Datei um und Du siehst was ich meine.
Hellstorm
User
Beiträge: 231
Registriert: Samstag 22. Juni 2013, 15:01

Wie? Wie kann man das denn sonst machen?

Eine print-Funktion, deren Anwendungsbereich auf ASCII beschränkt ist, ist doch auf dem Stand von vor 30 Jahren. Ich kann mir nicht vorstellen, dass das nicht irgendwie geht.

Wie würde man denn dann x-beliebigen Text auf der Konsole ausgeben?


Bei meinem Webhoster kriege ich übrigens ohne Probleme Statusmeldungen von meinem Cronjob, bei dem ein Python-Skript ausgeführt wird, das in der print-Funktion einen Umlaut ausgibt. Der cronjob schickt mir dann eine UTF-8-kodierte Mail, bei der der Umlaut korrekt angezeigt wird.
BlackJack

@Hellstorm: Irgendwo müssen Texte in Bytes umgewandelt werden wenn sie das Programm verlassen beziehungsweise von Bytes in Text wenn sie das Programm betreten. Und an der Stelle muss man wissen wie die Kodierung für diesen Übergang sein soll. Und da gibt es nichts einheitliches und auch keinen allgemeinen Weg wie man diese Information mit den Bytes überträgt oder speichert. Und darum geht das halt nicht. Du musst wissen was das Programm auf der „anderen Seite” als Kodierung erwartet/versteht. In einigen Fällen kann man das abfragen oder raten, aber halt nicht in allen.

Bei Deinem Webhoster wird sehr wahrscheinlich von jedem der beteiligten Programme UTF-8 geschrieben und erwartet und dann funktioniert das natürlich.
Hellstorm
User
Beiträge: 231
Registriert: Samstag 22. Juni 2013, 15:01

Naja, das mit der Umwandlung in Bytes ist ja klar. Aber im Endeffekt interessiert mich das ja in diesem konkreten Fall nicht. Ich will ja einfach nur jedes x-beliebige Zeichen auf der Konsole anzeigen (und auch auf der Standardeingabe entgegennehmen). Geht das denn dann überhaupt? Bzw was müsste ich dafür einstellen?

Ich kann mir aber nicht vorstellen, dass das nicht gehen sollte. ISO-8859-1 geht ja auch, wieso dann kein UTF-8? Ich will doch dann im Grunde nur einstellen, dass die Konsole unter Windows UTF-8 kann. Dann sollte das doch kein Problem sein, oder nicht? Mir geht es nur darum, wie ich das einstelle. Wenn ich das nur einmal machen muss , reicht mir das auch.
BlackJack

@Hellstorm: Natürlich interessiert Dich die Umwandlung in Bytes, denn genau das ist ja das Problem. Python muss wissen was das Programm auf der anderen Seite der `sys.stdout`-Datei als Kodierung erwartet, denn in diese Datei muss Python *Bytes* schreiben. Was anderes kann man nicht in Dateien schreiben. Und dazu müssen Text kodiert werden. Und zwar in der gleichen Kodierung die das Programm auf der anderen Seite erwartet. Und es gibt keinen allgemeingültigen Weg diese Information zu ermitteln. Was meinst Du mit ISO-8859-1 geht? Das ist vielleicht zufällig die Kodierung die das Programm auf der anderen Seite erwartet?
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Dein Windows benutzt als Standardkodierung fuer `cmd.exe` Codepage 850 (darum `File "C:\Programmieren\Python33\lib\encodings\cp850.py"` als Teil des Tracebacks) was natuerlich dein Zeichen nicht darstellen kann (ISO-8859-1 auch nicht, aber das ist zufaelligerweise grossteils mit CP 850 deckungsgleich).

Du kannst allerdings zur UTF-8 Codepage mittels `chcp 65001` wechseln http://msdn.microsoft.com/en-us/library ... 85%29.aspx
Benutzeravatar
pillmuncher
User
Beiträge: 1527
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

Ich habe Cygwin + Vcxsrv installiert und verwende für sowas urxvt-X. Das sieht dann so aus:

Bild
In specifications, Murphy's Law supersedes Ohm's.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Was ist denn mit der Powershell? Imho ein zu unrecht unbekanntes MS Produkt ;-) (Ok, es gibt natürlich bessere Shells, aber im Gegensatz zur CMD.exe eine Wohltat - inkl. Unixoiden Aliasen :-) )
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

cofi hat geschrieben:Dein Windows benutzt als Standardkodierung fuer `cmd.exe` Codepage 850
Sicher? Worin unterscheidet sich denn das von "cp1252"? Ich hatte dieses im Kopf...
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Um, CP 850 und CP 1252 unterscheiden sich _ziemlich_. Mit ersterem kann man hierzulande ja nichtmal Rechnungen stellen ;)

@Powershell .. na wenn du sie noch bis zum Internet-Sendeschluss gestartet bekommst *duck*
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Hehe... naja, wie oft startet man schon ne Shell ;-)

Und woher nimmst Du die Info, dass CP850 nun der Standard unter Windows ist?
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

@Hyperion: CP850 ist meiner Erfahrung nach der Standard *in der Eingabeaufforderung*. Zumindest für Deutschland/Westeuropa. Da müssen ja DOS-Programme drin laufen können und die gewohnten Zeichen ausgeben können. :-)
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Na wenn sie so lange zum starten brauch, selten .. sonst .. immer wenn noetig :)

Das das Windows-Standard ist, sagte ich nicht. Dafuer die Fehlermeldung sagt, dass _sein_ Terminal CP 850 spricht (oder zumindest so angesprochen wird) ;)

Zum Standard: "cmd.exe" ist die _DOS_-Eingabeaufforderung, 1252 eine Windows CP, 850 eine DOS CP. Insofern stimme ich da mal BlackJack zu :)
Hellstorm
User
Beiträge: 231
Registriert: Samstag 22. Juni 2013, 15:01

@BlackJack:

Ich hab mir jetzt noch mal überlegt, was du da eigentlich geschrieben hast, aber das ergibt doch absolut gar keinen Sinn. Du schreibst:
BlackJack hat geschrieben:@Hellstorm: Irgendwo müssen Texte in Bytes umgewandelt werden wenn sie das Programm verlassen beziehungsweise von Bytes in Text wenn sie das Programm betreten.
Aber was sind denn Texte überhaupt? Und was sind Bytes? Ein Text ist doch einfach nur eine Aneinanderreihung von Zeichen, die halt in irgendeiner Zeichenkodierung kodiert werden. Ein „A“ sitzt doch einfach nur an der Position 61 (bzw. 41 in Hex) und ist dementsprechend in Bytes kodiert. Das kann doch an gar keiner Stelle irgendwo als „Text“ kodiert werden und ist immer in Bytes. Selbst im Programmtext ist es doch als Bytes gespeichert (Im Arbeitsspeicher weiß ich nicht genau, aber da geh ich auch mal davon aus).

Und ob das jetzt in ASCII oder UTF-8 ist, ist doch egal. Bei UTF-8 ist doch nur der Unterschied, dass es eine variable Länge ist, also dass 1 Byte nicht unbedingt 1 Buchstabe ist (diese Annahme ist sowieso sehr unrealistisch).

Und die Konsole nimmt doch natürlich immer Zeichen als kodierte Bytes entgegen. Wie sollte sie es denn auch anders machen? Sie könnte natürlich auch direkt die Zeichen als Bitmap entgegennehmen, aber das würde ja bedeuten, dass das Programm schon entscheidet, wie die Zeichen aussehen sollten. Das tut es aber nicht, weil man ja den Text kopieren kann, weil man in der Konsole die Schriftart umstellen kann usw. Du schreibst ja später auch, dass die Konsole in CP850 kodiert ist.

Irgendwie passte das, was du aber auch sagst, ja gar nicht zu meiner Frage. Ich wollte ja nur wissen, wie genau ich es denn jetzt bewerkstelligen kann, halt allen möglichen Text auszugeben. Die technischen Details interessieren mich zum gegenwärtigen Zeitpunkt halt nicht. Eine Einstellung à la „Die Konsole nimmt ab jetzt Zeichen in UTF-8 entgegen“ und damit wäre es auch getan.

Übrigens funktioniert das weiterleiten in Linux ohne Probleme:

Code: Alles auswählen

$ python3 test.py > bla.txt
$ cat bla.txt
日本語
Auch mit einem Hex-Editor ist der richtige Inhalt UTF-8 kodiert enthalten: E6 97 A5 E6 9C AC E8 AA 9E 0A

D.h. es klappt wunderbar ohne Probleme, UTF-8-Strings auf der Konsole unter Linux mit Python zu verwenden. Ich muss mich dort auch um absolut nichts hinsichtlich der Kodierung kümmern, ich benutze einfach eine x-beliebige Sprache im Programmtext und lasse mir den dann auf die Konsole ausgeben. Da dort alles UTF-8 entgegennimmt, kann ich es ohne Probleme weiterverarbeiten und alles stimmt.
cofi hat geschrieben:Dein Windows benutzt als Standardkodierung fuer `cmd.exe` Codepage 850 (darum `File "C:\Programmieren\Python33\lib\encodings\cp850.py"` als Teil des Tracebacks) was natuerlich dein Zeichen nicht darstellen kann (ISO-8859-1 auch nicht, aber das ist zufaelligerweise grossteils mit CP 850 deckungsgleich).

Du kannst allerdings zur UTF-8 Codepage mittels `chcp 65001` wechseln http://msdn.microsoft.com/en-us/library ... 85%29.aspx
Ah genau, so etwas wollte ich wissen, danke :) Ich hatte mir jetzt nur gedacht, dass ich, weil ich dieses ConEmu hatte, was auch ziemlich gut klappt, so etwas nicht mehr bräuchte (japanische Dateinamen werden dort nämlich richtig dargestellt). Aber anscheinend ist das mit der Zeichenkodierung noch einmal etwas anderes.

Jetzt klappt es übrigens anscheinend auch (mehr oder weniger), es gibt allerdings noch einige kleinere Schönheitsfehler, da werde ich mich mal nachher dranmachen.
pillmuncher hat geschrieben:Ich habe Cygwin + Vcxsrv installiert und verwende für sowas urxvt-X. Das sieht dann so aus:
Genau so will ich es ja auch haben. Genau darum geht es mir, deswegen versteh ich nicht, wieso BlackJack meint, dass das nicht möglich sein sollte.
Hyperion hat geschrieben:Was ist denn mit der Powershell? Imho ein zu unrecht unbekanntes MS Produkt ;-) (Ok, es gibt natürlich bessere Shells, aber im Gegensatz zur CMD.exe eine Wohltat - inkl. Unixoiden Aliasen :-) )
Naja, Powershell ist ja wieder was anderes. Ich hab da (noch) keine Erfahrung mit, will das aber auch mal irgendwann zumindest in Grundzügen lernen. Allerdings geht es mir eher um das Konsolenfenster, und das ist bei der Powershell die gleiche wie bei der cmd.exe.

Danke für eure Antworten :)
Sirius3
User
Beiträge: 18216
Registriert: Sonntag 21. Oktober 2012, 17:20

@Hellstrom: Programm A übergibt Text an Programm B. In welchem Encoding der Text übergeben wird, sollten die beiden Programme vorher ausmachen. Mit Deinem Ansatz hast Du Glück, wenn die Konsole UTF-8-codierten Text entgegen nimmt. Das ist aber bei weitem nicht überall der Fall, gerade unter Linux. Wann es bei Dir klappt, ist also Zufall.
Erst Bytes+Encoding ergibt sinnvollen Text. Programmiersprachen, die das von Haus aus unterstützen (Python, Java), haben einen speziellen Datentyp für Text und einen für Bytes, weil es eben nicht dasselbe. Wie Text intern realisiert wird, kann für Dich egal sein, dass es aber einen Unterschied zwischen Text und Bytes gibt, ganz und gar nicht.
Außerhalb von Programmen gibt es nur Bytes. Wenn also Text aus einem Programm raus soll, z.B. auf die Konsole, dann nur als Bytes+Encoding, wobei das Encoding eben getrennt von den Bytes ausgehandelt werden muß.
Hellstorm
User
Beiträge: 231
Registriert: Samstag 22. Juni 2013, 15:01

Deswegen ist es ja wunderschön, wenn alle Programme UTF-8 können. Man muss sich dann eben nicht um irgendwas kümmern. Im übrigen hat mittlerweile jede halbwegs verbreitete Linux-Distribution UTF-8 als Standard (glücklicherweise). Linux ist da zwar immer sehr langsam (Debian hat UTF-8 erst 2006 oder 2007 als Standard benutzt; Windows schon mit NT 4.0 im Jahr 1996), aber im Allgemeinen ist das mittlerweile überall der Standard (oder zeigt mir bitte ein Gegenbeispiel). Und das auch zum Glück: Die ganzen anderen Kodierungen sind einfach nur ein Krampf, weil man dann wieder irgendeine Sprache nicht benutzen kann (Wer sich über ein paar fehlgeschlagene Umlaute ärgert, soll sich mal vorstellen, wie es ist, wenn man eine gesamte Sprache nicht schreiben kann).

Deswegen ist es auch kein Zufall. Das ist mittlerweile normal. Ich habe noch keine Linux-Distri der letzten Jahre erlebt, wo das nicht geklappt hätte (bitte immer Gegenbeispiele). Natürlich mag es sein, dass ich bei Debian 1.1 oder Suse 1.0 das nicht mehr benutzen kann, aber dann denk ich mir: Bitte mach ein Upgrade, wir sind im Jahr 2013. Ansonsten hast du halt Pech, dass die Software nicht geht.

Bei Windows ist jetzt natürlich nur das Problem, dass die Konsole dort ein absolutes Schattendasein führt und praktisch gar keine Aktualisierung erfährt. Deswegen läuft die dort noch nicht standardmäßig als UTF-8. Aber was genau soll ich dagegen jetzt machen? Ich will, dass die Zeichen unterstützt werden, deswegen brauche ich UTF-8 und stelle das für mich ein. Eine Alternative gibt es da einfach nicht. Die Zeichen nicht zu benutzen und mich nur auf ASCII zu beschränken ist keine Option, sorry.
Sirius3 hat geschrieben: Erst Bytes+Encoding ergibt sinnvollen Text. Programmiersprachen, die das von Haus aus unterstützen (Python, Java), haben einen speziellen Datentyp für Text und einen für Bytes, weil es eben nicht dasselbe.
Was ist denn dann der Unterschied? Wenn ich einen Datentext für Text habe, ist es doch nur so, dass man das ganze leichter schreiben und behandeln kann (Ich will ja eben nicht immer jedes Mal „E6 97 A5 E6 9C AC E8 AA 9E 0A“ anstatt „日本語“ schreiben). „Text“ kann doch gar nicht gespeichert werden. Text ist doch einfach nur ein willkürliche Belegung von Bytes auf grafische Symbole (=Buchstaben), der Schlüssel dazu heißt „Zeichenkodierung“.

Natürlich ergibt erst Bytes (was sollte es denn sonst sein, was anderes als Bits/Bytes gibt es doch am PC nicht?) + Zeichenkodierung (+ eine Schriftart und die Darstellungsalgorithmen, damit man auch was sehen kann) sinnvollen Text. Das ist doch klar und ist auch kein Unterschied, ob ich jetzt ASCII, Shift-JIS oder UTF-8 nutze. Selbst C wandelt doch automatisch den Text von einem char in Bytes um (bzw. was heißt umwandeln, es wird so intern gespeichert). Ein Text ist doch daher im Grunde auch nur eine Sammlung von Integern. Ein C-Array ist doch beispielsweise auch einfach nur eine Aneinanderhängung von Integern, die man mit einer Zeichenkodierung dann wieder lesbar macht.

Text ist doch einfach nur eine Reihe von Bytes, die mit einer Zeichenkodierung von bzw. zu Bytes umgewandelt werden. Dafür ist die Zeichenkodierung doch da. In den meisten Fällen kann man von ASCII ausgehen, aber wenn man etwas umfangreicheres haben möchte, braucht man eben eine andere Kodierung. Aber da ist doch egal, was ich jetzt benutze, nur die Position und der Umfang der Tabelle unterscheidet sich (Natürlich gibt es manchmal noch etwas kompliziertere Sachen wie Multi-byte-Encodings oder Escape-Sequenzen, aber das können die Programme ja verstehen, wenn sie die entsprechende Kodierung können).


Ich sehe das ganze Problem hier irgendwie nicht. Ich will eigentlich nur wissen, wie man Python mit Unicode (ob das jetzt UTF-7, UTF-8, UTF-16 oder UTF-32 ist, ist egal) vernünftig auf einer Windows-Konsole nutzen kann. Unter Linux (lies: jede halbwegs gebräuchliche aktuelle Distribution) klappt es ohne Probleme, unter Windows allerdings nicht von Haus aus, da die Zeichenkodierung auf CP850 (o.ä.) steht. Dass man da jetzt meinetwegen die Kodierung aushandeln muss, ist klar, aber kein Hindernis. Genau das will ich ja wissen.
BlackJack

@Hellstorm: Mit der Umleitung in eine Datei hast Du einen schönen Fehler gezeigt den die Entwickler bei Python 3 IMHO gemacht haben. Alles „funktioniert” einfach. Pustekuchen, es funktioniert nur solange man sich auf dem selben System mit den selben Einstellungen bewegt. Das hast Du selbst doch schon festgestellt, dass es auf Windows nicht mehr funktioniert. Das selbe Programm kann dann plötzlich nicht mehr die selben Zeichen ausgeben oder in eine Datei umleiten oder Daten die es auf in eine Datei geschrieben hat, nicht mehr aus der selbst geschriebenen Datei lesen. Das automatische Kodieren mit ”der” “Systemkodierung“ lässt Leute denken sie müssten sich jetzt nicht mehr selber mit Text, Bytes, und Kodierungen beschäftigen, was Du ja nach eigener Aussage auch gar nicht tun willst. Das ist aber schlicht falsch, denn wenn man ein tatsächlich *funktionierendes* Programm schreiben will, dann muss man genau das selbe wie bei Python 2 machen — selber explipizit an den Übergängen zur Aussenwelt kodieren und dekodieren und die Kodierung zumindest optional konfigurierbar machen für die Fälle wo es keinen Weg gibt eine Kodierung zu ermitteln oder zu raten. In dem Punkt hat sich eigentlich *überhaupt nichts* geändert, ausser dass Anfänger und solche die sich nicht mit den schmutzigen Details beschäftigen wollen erst einmal eingelullt werden und dann behaupten das mit Unicode sei in Python 3 viel einfacher geworden. Ist es nicht. IMHO ist es schlechter geworden weil Python einem nicht früher mit einer entsprechenden Ausnahme auf die Finger haut wenn man sich nicht ordentlich um Unicode kümmert.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Interessanter Thread. Aber warum wird eigentlich nicht estmal auf http://wiki.python-forum.de/Von%20Umlau ... 0Encodings verwiesen?

Die Eingabeaufforderung ist keine Box um DOS Programme laufen zu lassen. Das geht schon längere Zeit nicht mehr. Dazu gibt es z.B. http://www.dosbox.com/ die ein echtes DOS emuliert.

Von https://de.wikipedia.org/wiki/Cmd.exe :
Es handelt sich bei cmd.exe um eine native Win32-Anwendung, daher ist der Name „DOS-Eingabeaufforderung“ irreführend: es wird zwar eine Kommandozeile für MS-DOS-Befehle zur Verfügung gestellt, die selbst allerdings nicht unter MS-DOS als Betriebssystem läuft
Ich denke aus Standard CodePage wird Latin-1 verwendet. Mit "chcp 65001" sollte man auf UTF-8 umschalten können...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Sirius3
User
Beiträge: 18216
Registriert: Sonntag 21. Oktober 2012, 17:20

jens hat geschrieben:Ich denke aus Standard CodePage wird Latin-1 verwendet. Mit "chcp 65001" sollte man auf UTF-8 umschalten können...
Schön, das bringt mein cmd-Fenster zum abstürzen. Scheint wohl ein untested feature zu sein.

@Hellstrom: Windows nutzt seit NT4.0 eine 16bit-Kodierung von Zeichen die weitestgehend mit Unicode übereinstimmt. Eine UTF-8-Unterstützung gibt es von Systemseite aus nicht. Das hat zur Folge, dass die meisten Systemprogramme damit nicht umgehen können.
Antworten