Seite 1 von 1

Dateien schreiben in ISO 8859-15

Verfasst: Dienstag 17. November 2009, 10:18
von dahaze
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

Verfasst: Dienstag 17. November 2009, 10:59
von 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>

Verfasst: Dienstag 17. November 2009, 13:00
von dahaze
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?

Verfasst: Dienstag 17. November 2009, 13:10
von cofi
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.

Verfasst: Dienstag 17. November 2009, 13:28
von BlackJack
Ich verstehe nicht so recht, warum hier mit Unicode gearbeitet wird, wo es doch ziemlich offensichtlich Operationen auf Bytes sind!?

Verfasst: Dienstag 17. November 2009, 13:30
von dahaze
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?

Verfasst: Dienstag 17. November 2009, 13:38
von ms4py
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.

Verfasst: Dienstag 17. November 2009, 14:20
von dahaze
@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

Verfasst: Dienstag 17. November 2009, 14:37
von cofi
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.

Verfasst: Dienstag 17. November 2009, 17:18
von dahaze
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:

Verfasst: Dienstag 17. November 2009, 18:43
von 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.

Verfasst: Dienstag 17. November 2009, 20:00
von b.esser-wisser
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)

Verfasst: Dienstag 17. November 2009, 22:54
von ms4py
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...

Verfasst: Dienstag 17. November 2009, 23:10
von tordmor
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')
€

Verfasst: Dienstag 17. November 2009, 23:19
von ms4py
Ä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)

Verfasst: Montag 23. November 2009, 10:34
von dahaze
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

Verfasst: Montag 23. November 2009, 20:03
von BlackJack
Wenn Du einen String zurückhaben möchtest, solltest Du das `result` vielleicht nicht als Unicode-Objekt erstellen.

Verfasst: Dienstag 24. November 2009, 11:27
von dahaze
das stimmt allerdings.... :roll: