Dateien schreiben in ISO 8859-15

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.
Antworten
dahaze
User
Beiträge: 75
Registriert: Freitag 13. März 2009, 10:57
Wohnort: im Schwabenland

Hallo zusammen!

Ich steh malwieder vor einem Problem und komm einfach nicht drauf! :roll:
Eigentlich dachte ich, ich hätt das Thema mit den Encodings mittlerweile überwunden aber es holt mich doch immer wieder ein! :wink:

Zu meinem Problem:
Ich verschlüssele Strings mit einer Methode ähnlich der von Hannes unter http://www.python-forum.de/topic-5224.html

Funktioniert soweit auch ganz gut....

Nun würde ich gerne den String in eine Datei in der ISO 8859-15 Zeichencodierung schreiben und benutze hierzu:

Code: Alles auswählen

codecs.open('Zieldatei.dat','wb', 'iso-8859-15').write(cr.crypt(quelle))
"cr.crypt(quelle)" liefert mir den verschluesselten String...

Manchmal gehts gut, manchmal bekomm ich die Exception:

Traceback (most recent call last):
File "<MeinVerz>\crypt.py", line 322, in ?
main()
File ""<MeinVerz>\crypt.py", line 311, in main
ziel2 = codecs.open(sys.argv[2]+'2','wb', 'iso-8859-15').write(cr.crypt(quelle))
File "X:\PYTHON22\lib\codecs.py", line 338, in write
return self.writer.write(data)
File "X:\PYTHON22\lib\codecs.py", line 137, in write
data, consumed = self.encode(object, self.errors)
File "X:\PYTHON22\lib\encodings\iso8859_15.py", line 18, in encode
return codecs.charmap_encode(input,errors,encoding_map)
UnicodeError: charmap encoding error: character maps to <undefined>


Nach ein einiger Zeit bin ich hierauf gekommen:

Bekanntlich unterscheidet sich ISO-8859-15 ja nur geringfügig von ISO-8859-1 (s.a. http://de.wikipedia.org/wiki/ISO_8859-15 - die große Tabelle) und ich habe festgestellt, dass die Exception nur dann auftritt, wenn ich durch die "Verschlüsselung" genau eines dieser sich von ISO-8859-1 unterscheidenden Zeichen erwisch. :!:

Als ob versucht wird die Datei als ISO-8859-1 statt ISO-8859-15 zu schreiben :?:

Könnt ihr mir da vielleicht helfen?
Danke schonmal im Vorraus!

Gruß,
Simon
BlackJack

@dahaze: Du versuchst ein Zeichen als ISO-8859-15 zu kodieren, welches es in der Kodierung nicht gibt. Das geht halt nicht.

Code: Alles auswählen

In [2]: a = u'½'

In [3]: a.encode('iso-8859-1')
Out[3]: '\xbd'

In [4]: a.encode('iso-8859-15')
---------------------------------------------------------------------------
<type 'exceptions.UnicodeEncodeError'>    Traceback (most recent call last)

/home/bj/<ipython console> in <module>()

/home/bj/encodings/iso8859_15.py in encode(self, input, errors)

<type 'exceptions.UnicodeEncodeError'>: 'charmap' codec can't encode character u'\xbd' in position 0: character maps to <undefined>
dahaze
User
Beiträge: 75
Registriert: Freitag 13. März 2009, 10:57
Wohnort: im Schwabenland

Danke BlackJack! :roll:

Irgendwie sieht man beim Programmieren mit der Zeit den Wald vor lauter Bäumen nicht mehr! :wink:

Mein Problem hatte folgenden Ursprung:
Im Code von Hannes wurde folgende Methode benutzt um den neuen String zu erstellen:

Code: Alles auswählen

   for i in range(len(zk)):
                    c=ord(zk[i])+ord(code[i])
                    if c>255: c-=(256-null)
                    ausgabe+=unichr(c)
 
Dies hatte zu Folge, dass durch "unichr(c)" u.U. ein Unicodezeichen erstellt wurde dessen Abbild unter ISO-8859-15 nicht verrfügbar ist!
Beim encoden in ISO-8859-15 lief es dann ins Leere. :?

Nur durch was kann ich dann "ausgabe+=unichr(c)" ersetzen um einen "ISO-8859-15" konformen Unicodestring zu bekommen?
Sprich dass alle Zeichen in ISO-8859-15 darstellbar sind?
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Was spricht denn gegen eine UTF-8 Kodierung?

Deine Schleife laesst sich mit `enumerate` schoener loesen (das geht auch noch schoener)

Code: Alles auswählen

for i, z in enumerate(zk):
    c = ord(z) + ord(code[i])
    if c > 255: 
        c -= 256 - null
    ausgabe += unichr(c)
Und PEP8 solltest du dir auch mal anschaun.
BlackJack

Ich verstehe nicht so recht, warum hier mit Unicode gearbeitet wird, wo es doch ziemlich offensichtlich Operationen auf Bytes sind!?
dahaze
User
Beiträge: 75
Registriert: Freitag 13. März 2009, 10:57
Wohnort: im Schwabenland

Den Code hatte ich nur aus Hannes bespiel kopiert.

Bei mir siehts momentan so aus:

Code: Alles auswählen

      for i in xrange(0, len(data)):
          zeichenIdx = ord(data[i]) + ord(ck[i])
          if zeichenIdx > 255:
            zeichenIdx -= (256 - null)
          result += unichr(zeichenIdx)
Enumerate kann ich leider nicht benutzen, da ich auf Python 2.2 festgenagelt bin. Da gabs das noch nicht.... ;)

UTF-8 habe ich mir auch schon gedacht, das hätt auch von Anfang an funktioniert.
Aber benötigt da ein Zeichen nicht doppelt so viel Speicherplatz? Oder ist das nur, wenn ich mit dem Index die 0xFF überschreite?
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

dahaze hat geschrieben: Aber benötigt da ein Zeichen nicht doppelt so viel Speicherplatz? Oder ist das nur, wenn ich mit dem Index die 0xFF überschreite?
Nein, 0x7F ;)
Von 0 -127 entspricht UTF-8 genau dem ASCII.
Ein Zeichen kann allerdings auch bis zu 4 Byte benötigen und nicht nur 2.
dahaze
User
Beiträge: 75
Registriert: Freitag 13. März 2009, 10:57
Wohnort: im Schwabenland

@ice2k3:
Da ja grundlegend eh schon in ISO8859 codieren wollte, bin ich generell ja schon von 1 Byte/Zeichen ausgegangen. Deshalb 0xFF.
Aber da UTF-8 dann wohl dynamisch ist, benötige ich genauso viel Speicherplatz wie in ISO8859 solange ich mich im Zeichensatz auf Indize zwischen 0-255 beschränke.
Wird dann wohl das Beste sein, wenn ich es so löse.

Nichts desto trotz würde es mich interessieren, wie man in Python die Repräsentation eines Codes in einem bestimmten Zeichensatz erhält?
"chr()" gibt das Ascii-Zeichen zurück
"unichr()" gibt das Unicode-Zeichen zurück

....und wenn ich einen anderen Zeichensatz benötige? :)

Gruß,
Simon
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Unicode != UTF-(8,16,32)

Mit `unichr` erzeugst du einen Unicode-String, der das Zeichen am uebergebenen Codepoint besitzt, den kannst du in alle moeglichen Kodierungen serialisieren, wenn du das willst.
dahaze
User
Beiträge: 75
Registriert: Freitag 13. März 2009, 10:57
Wohnort: im Schwabenland

Genau diesen Codepoint hätte ich dann gerne von einer anderen Codierung! :D
Wenn ich z.B. Folgendes mache:

Code: Alles auswählen

print unichr(164)
Ergibt das das Zeichen ' ¤ '. Dies ist das korrekte Zeichen der Codepoints 164 in Unicode.

Wenn ich allerdings das Zeichen des Codepoints '164' der ISO 8859-15 haben will, wie mach ich das?

Code: Alles auswählen

unichr(164).encode('iso-8859-15')
funktioniert ja nicht, da es das Zeichen ' ¤ ' in der ISO nicht gibt.
Ich hätt in diesem Fall aber gerne das "€" Zeichen was den Codepoint 164 in der ISO-8859-15 besitzt !?
Das war ja mein ursprüngliches Problem.... :roll:
BlackJack

@dahaze: Nochmal die Frage: Du arbeitest auf Werten zwischen 0 und 255, warum also nicht auf Bytes statt auf Zeichen!? Ich sehe da keinen Vorteil.
Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

Ich hätt in diesem Fall aber gerne das "€" Zeichen was den Codepoint 164 in der ISO-8859-15 besitzt !?
Wenn du jetzt die ganze Zeit "chr()" gesucht hast, wirst du dir hoffentlich in den Hintern beißen (und lies den exzellenten Wiki-Artikel dazu)
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

b.esser-wisser hat geschrieben:
Ich hätt in diesem Fall aber gerne das "€" Zeichen was den Codepoint 164 in der ISO-8859-15 besitzt !?
Wenn du jetzt die ganze Zeit "chr()" gesucht hast, wirst du dir hoffentlich in den Hintern beißen (und lies den exzellenten Wiki-Artikel dazu)
Nein, hat er nicht... Das gibt ja ASCII zurück und nicht das gewünschte Encoding, außerdem hat er das auch schon erwähnt ;)

Mir geht es wie BlackJack, ich habe jetzt verstanden, was du willst, aber mir erschließt sich der Sinn dahinter nicht wirklich...
tordmor
User
Beiträge: 100
Registriert: Donnerstag 20. November 2008, 10:29
Wohnort: Stuttgart

dahaze hat geschrieben: Ich hätt in diesem Fall aber gerne das "€" Zeichen was den Codepoint 164 in der ISO-8859-15 besitzt !?
Das war ja mein ursprüngliches Problem.... :roll:
Unabhängig davon, dass auch ich den Sinn nicht völlig verstehe:

Code: Alles auswählen

>>> print chr(ord(unichr(164))).decode('iso-8859-15')
€
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

Ähm ja, das hat mich zuerst richtig gewundert.
Es geht aber auch so:

Code: Alles auswählen

>>> print chr(164).decode('iso-8859-15')
€
(``ord`` ist ja die Umkehrfunktion von ``unichr``, logisch dass man das weglassen kann)
dahaze
User
Beiträge: 75
Registriert: Freitag 13. März 2009, 10:57
Wohnort: im Schwabenland

Hallo zusammen!

Sorry, dass ich so lange eine Antwort schuldig blieb, hatte leider keine Zeit.

Ich bin eigentlich davon ausgegangen, dass ich meiner Methode generell einen String übergebe und von der wieder einen String zurückerhalte. Diesen dann halt iso-8859-15 konform....

Wenn ich mir meine Versuche genauer anschauen komme ich irgendwie zum Schluss, dass ich mir die Doku hätte genauer durchlesen sollen! :roll:
Ich bin irgendwie intuitiv davon ausgegangen, dass unichr() und chr() prinzipiell für Zeichen bis 255 das Gleiche zurückgibt!

Code: Alles auswählen

>>> print unichr(164)
¤
>>> print chr(164)
¤
Aber das stimmt ja so nicht, da

Code: Alles auswählen

>>> type(chr(164))
<type 'str'>
>>> type(unichr(164))
<type 'unicode'>
Somit "befinde" ich mich ja in der decode-encode Geschichte -wie in dem Wikiartikel beschreiben- an unterschiedlichen Punkten. :idea:
Denke jetzt hats geschnaggelt! :wink:

@BlackJack
Würde ich das einfacher lösen können wenn ich direkt auf Bytes arbeite?
Wie gesagt ich gehe eigentlich davon aus, dass ich an die Methode einen String übergebe und auch wieder zurückbekomme und "intern" arbeite ich ja eigentlich auf Bytes, oder?

Code: Alles auswählen

# hier string
for i in xrange(0, len(data)):
  #Bytes       
  zeichenIdx = ord(data[i]) + ord(ck[i])
  if zeichenIdx > 255:
    zeichenIdx -= 256
  #String
  result += unichr(zeichenIdx)
Danke für bisher eingesetzten Hirnschmalz! :D

Gruß,
Simon
BlackJack

Wenn Du einen String zurückhaben möchtest, solltest Du das `result` vielleicht nicht als Unicode-Objekt erstellen.
dahaze
User
Beiträge: 75
Registriert: Freitag 13. März 2009, 10:57
Wohnort: im Schwabenland

das stimmt allerdings.... :roll:
Antworten