Hallo, ich mal wieder.
Diesmal zwei kleine Fragen zu Unicode und utf-8.
Ich habe folgendes:
- einen Unicode-String (ja, wirklich)
- und ein externes Programm das diesen string als argument erhält
Mein Problem:
Im String ist ein ä, ich encodiere ihn mit utf-8, verbinde ihn mit weiteren utf-8 strings und starte das programm.
Doch das Programm verweigert den Start, weil das ä kein ä ist, sondern \xc3\xa4.
Ist wohl nurn Verständnisproblem, blicke zwar inzwischen "ganz grob" durch bei diesem Thema, aber scheinbar halt doch noch nicht so perfekt.
Deshalb nun die Fragen:
- Das "ä" ist der Char(akter) bzw. Glyph zur grafischen Darstellung, also dem was "ich" sehe. Das utf-8 Code-Point Äquivalent \xc3\xa4 ist das was python "sieht" und auch weitergibt wenn ich mit subprocess das Programm starte, richtig?
- Angenommen es ist richtig, wie sag ich dann python es soll nicht den Code-Point sondern den Charakter mit subprocess verwenden?
unicode und encodings, wie so oft..
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Zunächst einmal viel Lektüre, wie immer bei dem Thema:
http://wiki.python-forum.de/Von%20Umlau ... 0Encodings
http://wiki.python-forum.de/User%20Grou ... folien.pdf
Weißt Du denn, welches Encoding das externe Programm erwartet? Vermutlich kann es eben nicht mit uft-8 umgehen...
Generell solltest Du intern solange wie möglich mit unicode arbeiten und nicht mit Byte-Strings, wie Du es beschrieben hast. Konkateniere alles in Unicode und wandle erst ganz am Schluss in ein passendes Encoding.
Zu den Fragen am Schluss: Python gibt eben einen Bytestring in utf-8 codierter Form an das andere Programm weiter. Das "ä" ist nur ein Zeichen, welches eine Byte-Sequenz im Bytestring als durckbares Zeichen darstellt. Im Rechner werden aber eben Bytes weitergegeben, keine druckbaren Zeichen. Insofern kannst Du Python da nichts anderes beibringen. Aber Du kannst eben prüfen, was das andere Programm so als Encoding akzeptiert.
http://wiki.python-forum.de/Von%20Umlau ... 0Encodings
http://wiki.python-forum.de/User%20Grou ... folien.pdf
Weißt Du denn, welches Encoding das externe Programm erwartet? Vermutlich kann es eben nicht mit uft-8 umgehen...
Generell solltest Du intern solange wie möglich mit unicode arbeiten und nicht mit Byte-Strings, wie Du es beschrieben hast. Konkateniere alles in Unicode und wandle erst ganz am Schluss in ein passendes Encoding.
Zu den Fragen am Schluss: Python gibt eben einen Bytestring in utf-8 codierter Form an das andere Programm weiter. Das "ä" ist nur ein Zeichen, welches eine Byte-Sequenz im Bytestring als durckbares Zeichen darstellt. Im Rechner werden aber eben Bytes weitergegeben, keine druckbaren Zeichen. Insofern kannst Du Python da nichts anderes beibringen. Aber Du kannst eben prüfen, was das andere Programm so als Encoding akzeptiert.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
assert encoding_kapiert
Dein erstes Verständnisproblem ist, dass du die Fehlermeldung und Code nicht postet.Gremlin hat geschrieben:Im String ist ein ä, ich encodiere ihn mit utf-8, verbinde ihn mit weiteren utf-8 strings und starte das programm.
Doch das Programm verweigert den Start, weil das ä kein ä ist, sondern \xc3\xa4.
Ist wohl nurn Verständnisproblem, blicke zwar inzwischen "ganz grob" durch bei diesem Thema, aber scheinbar halt doch noch nicht so perfekt.
Ja.- Das "ä" ist der Char(akter) bzw. Glyph zur grafischen Darstellung, also dem was "ich" sehe.
Nein. "\xc3\xa4" ist ein Bytestring der Länge zwei, mehr nicht und darin liegt auch das Problem, weil du damit anscheinend irgendwas machen willst, wofür er nicht gemacht ist. Aber hier fehlen Fehlermeldung und Code.Das utf-8 Code-Point Äquivalent \xc3\xa4 ist das was python "sieht" und auch weitergibt wenn ich mit subprocess das Programm starte, richtig?
Indem du den String nicht vorher in utf8 codierst bzw. ihn im anderen Programm wieder dekodierst. Aber darüber zu spekulieren was du machen musst ist müßig solange du die Fehlermeldung + Beispielcode nicht postest.- Angenommen es ist richtig, wie sag ich dann python es soll nicht den Code-Point sondern den Charakter mit subprocess verwenden?
Das war der Knackpunkt. Hab bisher nur in die Richtung gedacht was mein Programm erwartet (Das externe will iso-8859-1)Hyperion hat geschrieben:Weißt Du denn, welches Encoding das externe Programm erwartet? Vermutlich kann es eben nicht mit uft-8 umgehen...
Dann ergibt sich für mich da aber wieder ne Frage, und zwar wie soll ich das machen? Sehr viel in meinem Programmcode besteht aus konstanten strings und die hab ich mit einem cookie als utf-8 ausgewiesen. Kann ich die auch per cookie als unicode ausweisen oder muss ich dann wirklich überall das "u" vorne dran hängen? (Mein Gefühl sagt mir zwar, ja, muss ich, aber fragen kostet ja nichts..)Hyperion hat geschrieben:Generell solltest Du intern solange wie möglich mit unicode arbeiten und nicht mit Byte-Strings, wie Du es beschrieben hast. Konkateniere alles in Unicode und wandle erst ganz am Schluss in ein passendes Encoding.
Naja, bei folgender Fehlermeldung (Das Programm ist übrigens 7zip) kann man (ich?) nicht viel verstehen: (Code 2) Fatal ErrorDarii hat geschrieben:Dein erstes Verständnisproblem ist, dass du die Fehlermeldung und Code nicht postet.
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Naja, im Quellcode steht ja nun einmal kein Unicode, sondern irgend welche Byte-Strings. (Wie schön aus den Folien von Leonidas hervorgeht und was auch ich erst mal begreifen musste ist ja grad der Witz, dass Unicode nur ein Konzept und keine Codierung zum Speichern darstellt.) Python muss nun ja wissen, mit welchem Encoding diese Strings im Programm stehen, damit der Interpreter das gante parsen kann. Standardmäßig wird bei Python 2.x ASCII angenommen; will man etwas anderes hilft das Festlegen des Encodings (es muss natürlich dann auch in dem Format gespeichert sein ).Gremlin hat geschrieben: Dann ergibt sich für mich da aber wieder ne Frage, und zwar wie soll ich das machen? Sehr viel in meinem Programmcode besteht aus konstanten strings und die hab ich mit einem cookie als utf-8 ausgewiesen. Kann ich die auch per cookie als unicode ausweisen oder muss ich dann wirklich überall das "u" vorne dran hängen? (Mein Gefühl sagt mir zwar, ja, muss ich, aber fragen kostet ja nichts..)
Unicode-Strings sind in Deiner Datei ja zunächst eben auch Bytestrings; damit Python diese automatisch decodieren kann, braucht es ebenfalls die Angabe des Encodings oben im Script Kopf. Somit kann der Interpreter aus den Bytestrings Deiner Code-Datei intern in Unicode wandeln.
Die simple Antwort lautet damit: Durch Festlegen des Encodings im Dateikopf, kannst Du eben Unicode-Strings in den Quellcode hinschreiben, die Umlaute usw. enthalten können, sofern das Endoding der Datei dieses zulässt. Python nimmt dann intern eben dieses Encoding und es klappt.
Kannst Du ja mal testen:
Code: Alles auswählen
#!/usr/bin/python
s = u"Hallöle"
Schreibst Du das Encoding rein, klappt es
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
assert encoding_kapiert
Wenn dir die Fehlermeldung nichts sagt, solltest du sie (+Code) erst Recht posten. Das verhindert nämlich unnötige Spekulationen seitens derjenigen die dir helfen wollen.Gremlin hat geschrieben:Naja, bei folgender Fehlermeldung (Das Programm ist übrigens 7zip) kann man (ich?) nicht viel verstehen: (Code 2) Fatal Error
Danke. So ganz langsam sitzt es, denke ich
Aber mal so nebenbei, die Folien von Leonidas hab ich mir angesehen, aber wirklich verstanden hab ich nicht viel. Ist ja schließlich in Form einer Präsentation aufgebaut (Stichpunkte, etc.) und um da wirklich durchzusteigen fehlen die dazugehörigen Erläuterungen, finde ich.
Aber mal so nebenbei, die Folien von Leonidas hab ich mir angesehen, aber wirklich verstanden hab ich nicht viel. Ist ja schließlich in Form einer Präsentation aufgebaut (Stichpunkte, etc.) und um da wirklich durchzusteigen fehlen die dazugehörigen Erläuterungen, finde ich.
Ich werds mir fürs nächste Mal merken.Darii hat geschrieben:Wenn dir die Fehlermeldung nichts sagt, solltest du sie (+Code) erst Recht posten. Das verhindert nämlich unnötige Spekulationen seitens derjenigen die dir helfen wollen.
Das ist aber auch nicht das richtige Encoding. Alle an suprocess.Popen/call übergebenen Strings sollten mit sys.getfilesystemencoding() kodiert werden. Unter Windows läuft das aufs Encoding 'mbcs' hinaus, unter Mac OS X (immer) und Linux (meist) auf UTF-8.Das externe will iso-8859-1
Der Grund, dass unter Windows für manche Zeichen auch iso-8859-1 stattdessen funktioniert, ist, dass bestimmte Codepoints überlappen, z.B.:
Code: Alles auswählen
>>> import sys
>>> u'ä'.encode('iso-8859-1')
'\xe4'
>>> u'ä'.encode(sys.getfilesystemencoding())
'\xe4'
Code: Alles auswählen
>>> u'\u2022'.encode(sys.getfilesystemencoding()) # \u2022 = • = Aufzählungszeichen
'\x95'
>>> u'\u2022'.encode('iso-8859-1')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'latin-1' codec can't encode character u'\u2022' in position 0: ordinal not in range(256)
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Woher weißt Du das?fhoech hat geschrieben:Das ist aber auch nicht das richtige Encoding.Das externe will iso-8859-1
In der Doku steht dazu aber nichts. Gibt es da eine Quelle oder eine Begründung?fhoech hat geschrieben: Alle an suprocess.Popen/call übergebenen Strings sollten mit sys.getfilesystemencoding() kodiert werden. Unter Windows läuft das aufs Encoding 'mbcs' hinaus, unter Mac OS X (immer) und Linux (meist) auf UTF-8.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
assert encoding_kapiert
Aus eigener Erfahrung.Hyperion hat geschrieben:Woher weißt Du das?fhoech hat geschrieben:Das ist aber auch nicht das richtige Encoding.Das externe will iso-8859-1
Leider nein. Ich hätte mir gewünscht, das dazu etwas in der Doku steht, oder das subprocess automatisch eine entsprechende Kodierung von Unicode-Strings vornimmt. Es funktioniert aber so zuverlässig. Um das wirklich technisch zu begründen, müsste man sich wahrscheinlich die entsprechenden Systemaufrufe für Dateinamenoperationen auf den jeweiligen Systemen ansehen. Ich würde mutmaßen, die meisten Programme sind was das angeht wahrscheinlich ziemlich 'dumm', sprich sie nehmen den/die übergebenen Dateiparameter als Bytestring entgegen und überlassen den Umgang damit den Systemaufrufen.Hyperion hat geschrieben:In der Doku steht dazu aber nichts. Gibt es da eine Quelle oder eine Begründung?fhoech hat geschrieben: Alle an suprocess.Popen/call übergebenen Strings sollten mit sys.getfilesystemencoding() kodiert werden. Unter Windows läuft das aufs Encoding 'mbcs' hinaus, unter Mac OS X (immer) und Linux (meist) auf UTF-8.
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Dann hast Du eine gute Glaskugelfhoech hat geschrieben:Aus eigener Erfahrung.Hyperion hat geschrieben:Woher weißt Du das?fhoech hat geschrieben: Das ist aber auch nicht das richtige Encoding.
Ich würde jetzt annehmen, dass das eben von Programm zu Programm unterschiedlich gehandhabt werden wird. Viele werden wohl das OS spezifische Encoding bei ihrer Annahme von externen Parametern annehmen, andere aber vielleicht nicht. Insofern denke ich nicht, dass Deine verallgemeinerte Aussage so Bestand haben kann - ich mag mich da auch irren, aber als PoC könnte man ja eben selber ein Programm schreiben, dass ein spezielle Encoding voraussetzt, welches sich vom OS default unterscheidet. Mir leuchtet es zumindest nicht ein, dass Dein Rezept als absoluter Maßstab gelten kann.fhoech hat geschrieben: Leider nein. Ich hätte mir gewünscht, das dazu etwas in der Doku steht, oder das subprocess automatisch eine entsprechende Kodierung von Unicode-Strings vornimmt. Es funktioniert aber so zuverlässig. Um das wirklich technisch zu begründen, müsste man sich wahrscheinlich die entsprechenden Systemaufrufe für Dateinamenoperationen auf den jeweiligen Systemen ansehen. Ich würde mutmaßen, die meisten Programme sind was das angeht wahrscheinlich ziemlich 'dumm', sprich sie nehmen den/die übergebenen Dateiparameter als Bytestring entgegen und überlassen den Umgang damit den Systemaufrufen.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
assert encoding_kapiert
@fhoech: Deine Erfahrung mag so sein, die Schlussfolgerungen die Du daraus ziehst stimmen aber nicht. `subprocess` kann nichts automatisch kodieren, weil eben nicht ermittelt werden kann, in welcher Kodierung die gestartete Anwendung die Kommandozeilenargumente erwartet. Das sind einfach nur Bytes und sowohl Aufrufer als auch Aufgerufener müssen von der selben Kodierung ausgehen. Es ist aber nirgends festgelegt welche das ist.
Naja, also das kann man durchaus testen (das ist der Weg, den ich gegangen bin). Alles was man dazu braucht, ist das entsprechende Programm und ein paar Dateien mit Namen, die einen gewissen Unicode-Bereich ausserhalb diverser Single-Byte-Encodings abdecken (die kann man ja auch programmatisch erzeugen).Dann hast Du eine gute Glaskugel
So war es auch nicht gedacht. Aber irgendwie kodiert muss man subprocess ja die Strings übergeben, und ehe man hier ein (auch nur geratenes) Encoding fest vorgibt, kann man sys.getfilesystemencoding() verwenden.Mir leuchtet es zumindest nicht ein, dass Dein Rezept als absoluter Maßstab gelten kann.
Ok, ich stehe auf dem Schlauch. Welche Schlussfolgerungen?BlackJack hat geschrieben:@fhoech: Deine Erfahrung mag so sein, die Schlussfolgerungen die Du daraus ziehst stimmen aber nicht.
Das bestreite ich ja auch nicht, bzw. habe nichts anderes behauptet. Ich wollte einfach einen Weg aufzeigen, der zuverlässig funktioniert (für die gegebene Anwendung, 7zip, aber eben meiner Erfahrung nach auch für andere).BlackJack hat geschrieben:`subprocess` kann nichts automatisch kodieren, weil eben nicht ermittelt werden kann, in welcher Kodierung die gestartete Anwendung die Kommandozeilenargumente erwartet. Das sind einfach nur Bytes und sowohl Aufrufer als auch Aufgerufener müssen von der selben Kodierung ausgehen.
Leider. Wäre das irgendwo dokumentiert, hätte ich mir einen Haufen zeitaufändige Tests sparen können (damals, als ich das erste Mal damit konfrontiert wurde ).Blackjack hat geschrieben:Es ist aber nirgends festgelegt welche das ist.
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Es ging aber darum, dass Du dem OP widersprochen hast, dass das "iso-8859-1" Encoding hier das erwartete ist. Und da der OP das Programm nicht genannt hat, dürfte das eben reines "raten" seinfhoech hat geschrieben:Naja, also das kann man durchaus testen (das ist der Weg, den ich gegangen bin). Alles was man dazu braucht, ist das entsprechende Programm und ein paar Dateien mit Namen, die einen gewissen Unicode-Bereich ausserhalb diverser Single-Byte-Encodings abdecken (die kann man ja auch programmatisch erzeugen).Dann hast Du eine gute Glaskugel
Edit: oops. Ok, sehe ich jetzt erst, dass er es doch genannt hat. Also magst Du hier doch recht haben
Ok, so formuliert klingt es schon ganz anders. Auch das ist ja eben nur "raten", wenn vielleicht auch ein ganz "gutes". Jedoch kannst Du dem OP ja nicht unterstellen, dass er geraten hat. Evtl. stand ja in der Doku zum speziellen Programm, was es erwartetSo war es auch nicht gedacht. Aber irgendwie kodiert muss man subprocess ja die Strings übergeben, und ehe man hier ein (auch nur geratenes) Encoding fest vorgibt, kann man sys.getfilesystemencoding() verwenden.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
assert encoding_kapiert
Ist mir bewusst. Deshalb schrieb ich ja auch "auch"Auch das ist ja eben nur "raten", wenn vielleicht auch ein ganz "gutes".
Das war ja jetzt keine "böswillige" Unterstellung (bzw. nicht so gemeint), und ich gebe zu, ich habe nicht extra in die 7zip-Doku geschaut. Aber Tatsache ist, das subprocess bei meinem Beispieldateinamen (mit u"\u2022") bei "iso-8859-1" einen Fehler wirft, daher meine Annahme (mit 'mbcs' oder eben sys.getfilesystemencoding funktioniert es).Jedoch kannst Du dem OP ja nicht unterstellen, dass er geraten hat. Evtl. stand ja in der Doku zum speziellen Programm, was es erwartet
Hm, ich hab aber geraten, naja gut, bevor ich diese Behauptung aufgestellt habe hab ichs schon getestet, aber beweisen könnt ichs trotzdem nicht
Zuletzt geändert von Gremlin am Montag 23. August 2010, 08:53, insgesamt 1-mal geändert.
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Naja, vielleicht liegt es auch daran, dass ISO 8859-1 einfach kein "U+2022 BULLET" kennt. Warum sollte es auch?fhoech hat geschrieben:Aber Tatsache ist, das subprocess bei meinem Beispieldateinamen (mit u"\u2022") bei "iso-8859-1" einen Fehler wirft, daher meine Annahme (mit 'mbcs' oder eben sys.getfilesystemencoding funktioniert es).
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Klar, das ist ja gerade der KnackpunktLeonidas hat geschrieben:Naja, vielleicht liegt es auch daran, dass ISO 8859-1 einfach kein "U+2022 BULLET" kennt. Warum sollte es auch?fhoech hat geschrieben:Aber Tatsache ist, das subprocess bei meinem Beispieldateinamen (mit u"\u2022") bei "iso-8859-1" einen Fehler wirft, daher meine Annahme (mit 'mbcs' oder eben sys.getfilesystemencoding funktioniert es).
Edit: Ups, da hab ich ja tatsächlich Blödsinn geschrieben, sorry. Hast natürlich recht, nicht subprocess wirft den Fehler, sondern natürlich die encode()-Methode. Hab mich da nicht gut ausgedrückt. Worauf ich eigentlich hinaus wollte, ist, dass Dateinamen Zeichen enthalten können, die nicht in (z.B.) ISO 8859-1 vorkommen.