ubuntuusers.de

Python: Umlaute und Formatstrings

Status: Gelöst | Ubuntu-Version: Ubuntu
Antworten |

zettberlin

Avatar von zettberlin

Anmeldungsdatum:
23. Oktober 2006

Beiträge: 623

Wohnort: Celle

Hallo Leute,

bastele gerade ein bisschen mit Python herum und habe folgendes Problem:

Wenn ich einen String direkt von raw_input mit write in einen Datei schreibe, kommen Umlaute völlig korrekt in der Datei an.

Mache ich es aber stattdessen so:

1
target.write("\n line1:%r \n line2:%r \n line3:%r \n " % (line1, line2, line3))

habe ich dieses Problem:

line1:'noch m\xc3\xa4hhr'

Dort sollte natürlich "Noch mähhr" stehen. Wie gesagt, wenn ich direkt target.write(line1) reinschreibe, funktioniert alles.

Was mache ich fälschlich?

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

Es deutet alles darauf hin, dass das Encoding Deiner Quelldatei nicht mit dem Encoding Deiner Shell übereinstimmt. Entweder Du passt das Encoding Deines Scriptes an, oder - was besser ist - Du wandelst das in Unicode und nutzt das das codecs-Modul, um dann beim Schreiben in eine Datei das Encoding explizit zu wählen.

Kinch

Anmeldungsdatum:
6. Oktober 2007

Beiträge: 1261

Schonmal %s statt %r probiert? Kennst du den Unterschied?

Die Python-Version, vor allem bei solchen Umlaut-Sachen ist übrigens auch wichtig. Python3 ist per default unicode, was einiges anders macht.

zettberlin

(Themenstarter)
Avatar von zettberlin

Anmeldungsdatum:
23. Oktober 2006

Beiträge: 623

Wohnort: Celle

Kinch schrieb:

Schonmal %s statt %r probiert?

huaahh – cool! Das war der Trick ☺

Kennst du den Unterschied?

Also ehrlich gesagt, werde ich aus den Erklärungen auf der python-seite nicht richtig schlau:

http://docs.python.org/library/stdtypes.html#string-formatting

In der Anmerkung wird zwar irgendwo unten genau mein Problem zumindest indirekt erklärt aber warum und wie...

Die Python-Version, vor allem bei solchen Umlaut-Sachen ist übrigens auch wichtig. Python3 ist per default unicode, was einiges anders macht.

Ich hab hier noch 2.6.5 Wird wohl besser sein, ich steige um...

Kinch

Anmeldungsdatum:
6. Oktober 2007

Beiträge: 1261

zettberlin schrieb:

Kinch schrieb:

Schonmal %s statt %r probiert?

huaahh – cool! Das war der Trick ☺

Kennst du den Unterschied?

Also ehrlich gesagt, werde ich aus den Erklärungen auf der python-seite nicht richtig schlau:

%r nutzt die repr-Funktion um ein Objekt in einen String zu konvertieren und %s nutzt die str-Funktion.

Die repr, für Representation, konvertiert ein beliebiges Python-Object zu einer String-Representation und zwar so, wie der Python-Interpreter das auch wieder einlesen kann. str konvertiert auch ein Python-Objekt zu einem String, aber zu einem String der von Menschen oder anderen Programmen wieder gelesen werden kann.

'\xc3\xa4' ist eine Schreibweise für den unicode-codepoint für 'ä'. Du kannst das sehen durch:

print 'noch m\xc3\xa4hhr'
noch mähhr

Intern werden Unicodes nicht durch Zeichen wie 'ä' sondern durch die \x oder \u Notation darsgestellt und desween, gibt repr auch diese Notation aus.

Ich hab hier noch 2.6.5 Wird wohl besser sein, ich steige um...

Na ja, python3 macht sich wegen der fehlenden Abwärtskompatibilität auch nicht nur Freunde.

zettberlin

(Themenstarter)
Avatar von zettberlin

Anmeldungsdatum:
23. Oktober 2006

Beiträge: 623

Wohnort: Celle

Kinch schrieb:

zettberlin schrieb:

Kinch schrieb:

Schonmal %s statt %r probiert?

huaahh – cool! Das war der Trick ☺

Kennst du den Unterschied?

Also ehrlich gesagt, werde ich aus den Erklärungen auf der python-seite nicht richtig schlau:

%r nutzt die repr-Funktion um ein Objekt in einen String zu konvertieren und %s nutzt die str-Funktion.

Die repr, für Representation, konvertiert ein beliebiges Python-Object zu einer String-Representation und zwar so, wie der Python-Interpreter das auch wieder einlesen kann. str konvertiert auch ein Python-Objekt zu einem String, aber zu einem String der von Menschen oder anderen Programmen wieder gelesen werden kann.

'\xc3\xa4' ist eine Schreibweise für den unicode-codepoint für 'ä'. Du kannst das sehen durch:

print 'noch m\xc3\xa4hhr'
noch mähhr

Intern werden Unicodes nicht durch Zeichen wie 'ä' sondern durch die \x oder \u Notation darsgestellt und desween, gibt repr auch diese Notation aus.

Ahhh – jetzt klärt sich der Nebel! Intern arbeitet Python also immer nur mit ASCII (oder Integer etc) und Unicode-Extras wie Umlaute oder Kyrillisch werden nur nach Außen für Menschlein bei Bedarf dargestellt – richtig? Vielen Dank ☺

Ich hab hier noch 2.6.5 Wird wohl besser sein, ich steige um...

Na ja, python3 macht sich wegen der fehlenden Abwärtskompatibilität auch nicht nur Freunde.

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

zettberlin schrieb:

Ahhh – jetzt klärt sich der Nebel! Intern arbeitet Python also immer nur mit ASCII (oder Integer etc) und Unicode-Extras wie Umlaute oder Kyrillisch werden nur nach Außen für Menschlein bei Bedarf dargestellt – richtig?

Nein! Wenn wir bei Python2 bleiben, arbeitet Python intern entweder mit Bytestrings oder mit Unicodestrings. Sobald irgend etwas auf irgend einem Medium ausgegeben wird (Shell, Datei), muss der rein im Speicher dargestellte Unicode in einen Bytestring gewandelt werden. Ein Bytestring hat immer eine bestimmte Codierung, also ASCII, iso-8859-x, utf-8, latin-1 usw. Je nach Encoding kann man also spezielle Zeichen wie Umlaute darstellen. utf-8 ist ein Encoding, welches alle Unicode-Code-Points darstellen kann. Insofern ist utf-8 das ideale Format, wenn man keine Probleme mit De- bzw. Encoding-Fehlern haben möchte.

Sinnvoll ist es in Python2 daher, so früh wie möglich aus einem Bytestring in einen Unicodestring zu decodieren, d.h. sobald man Daten aus einer externen Quelle bekommt (Datei, Usereingabe, Pipe, usw.) und möglichst spät in ein spezielles Encoding zu wandeln, d.h. sobald man Strings wieder speichern / ausgeben will.

Genau das habe ich Dir schon oben geraten.

Die repr Funktion stellt lediglich lesbare Escape-Sequenzen dar und garantiert damit, dass die Ausgabe sich immer im ASCII Bereich befindet. Dieser ist quasi der kleinste gemeinsame Nenner alles Codecs und daher auf jeder Maschine darstellbar. Insofern bringt Dir das wenig, wenn zwei Encodings vermischt werden (Quellcode liegt utf-8 vor und Eingabe erfolgt per iso-8859). Denn dann kracht es einfach.

Noch etwas zum generellen Verständnis:

Als letztes noch etwas fundamentales:

Unicode != utf-8

Das habe ich selber lange Zeit verwechselt. Also: Bytestrings sind immer in einem bestimmten Format (eben auch utf-8), Unicodestrings sind das universelle, aber nur interne Format, in dem alle Zeichen dieser Welt abbildbar sind. Kann mein Encoding alle Unicode-Zeichen darstellen (wie utf-8), dann habe ich beim encodieren keine Probleme. Beim decodieren habe ich logischer Weise keine, da Unicode eben alles beinhaltet.

Aber: Ich muss das Encoding für das korrekte Dekodieren wissen. Man kann zwar raten, aber das muss nicht klappen. Alleine aus Bytestrings kann man das Encoding nicht erkennen!

Antworten |