[Python-de] Isch habe verstanden

Walter Dörwald walter at livinglogic.de
Thu Nov 7 19:38:34 EST 2002


Gerson Kurz wrote:

> Ich weiß, ich weiß, ihr stöhnt sicher jetzt: kann der Depp nicht die Finger
> davon lassen, wenn er es nicht versteht? Warte es ab!
> 
> Also, ich habe das Programm (http://p-nand-q.com/python/out2xml.zip) jetzt
> erstmal funktionsfähig, und mir folgendes  vermutlich fehlgeleitete
> Verständnis erarbeitet.
> 
> # Zeichen sind jeweils zwei Byte lang (Little Endian)
> UNICODE_ENCODING = "utf-16le"
> 
> # Zeichen sind normalerweise ein Byte lang, Sonderzeichen per
> "Escapesequenz" auf mehrere Bytes verteilt.
> UNICODE_ENCODING = "utf-8"
> 
> # Zeichen sind jeweils ein Byte lang, Interpretation erfolgt abhängig von
> der Codepage. Wenn das Zeichen nicht in ein Byte (0..255) passt, gibt es
> eine Exception.
> UNICODE_ENCODING = "latin-1"

Nicht ganz: Bei Latin-1 ist die Codepage immer die Identität, d.h.
U+0000 -> 0x00
U+0000 -> 0x01
...
U+00ff -> 0xff

Wie andere Codepages aussehen, kannst Du Dir im Source angucken, z.B.
für iso-8859-15 in encodings/iso8859_16.py:

decoding_map = codecs.make_identity_dict(range(256))
decoding_map.update({
    0x00a4: 0x20ac, # EURO SIGN
    0x00a6: 0x0160, # LATIN CAPITAL LETTER S WITH CARON
    0x00a8: 0x0161, # LATIN SMALL LETTER S WITH CARON
    0x00b4: 0x017d, # LATIN CAPITAL LETTER Z WITH CARON
    0x00b8: 0x017e, # LATIN SMALL LETTER Z WITH CARON
    0x00bc: 0x0152, # LATIN CAPITAL LIGATURE OE
    0x00bd: 0x0153, # LATIN SMALL LIGATURE OE
    0x00be: 0x0178, # LATIN CAPITAL LETTER Y WITH DIAERESIS
})

d.h. z.B. daß das EURO-Zeichen U+20ac auf das Byte 0xa4 gemappt
wird.

> - Ein Unicodestring "weiß", daß in "Höher" das zweite Zeichen als "Kringel
> mit zwei Punkten drüber" dargestellt werden soll.

Genau: Jedes Unicodezeichen hat eine Nummer: Das "ö" z.B. 246 (==0xf6)
und einen Namen:

 >>> import unicodedata
 >>> unicodedata.name(u"\xf6")
'LATIN SMALL LETTER O WITH DIAERESIS'

> - Es gibt nicht nur eine Abbildung "Kringel mit zwei Punkten drüber" als
> Bytes.

Genau: Ein Encoding ist der Name einer Abbildungsvorschrift von
Sequenzen von Unicode-Nummern in Byte-Sequenzen (und umgekehrt)
und davon gibt es viele.

> - Deshalb muß ich encode() aufrufen, und erhalte dann aus dem "Wissenden
> Unicodestring" einen Bytebatzen in diesem Encoding. Beispiel (und da, glaube
> ich, habe ich es verstanden):
> 
> 
>>>>test = u"ö"
>>>>test
> 
> u'\x94'
> 
>>>>test.encode("utf-16le")
> 
> '\x94\x00'
> 
>>>>test.encode("utf-8")
> 
> '\xc2\x94'
> 
>>>>test.encode("latin-1")
> 
> '\x94'
> 
>>>>test.encode("ascii")
> 
> Traceback (most recent call last):
>   File "<stdin>", line 1, in ?
> UnicodeError: ASCII encoding error: ordinal not in range(128)
> 
> 
> Das erklärt meine Fragen 1 (der String *weiss nicht* welches Encoding er
> hat), und 2 (weil das genau der Zweck von encode ist) und 3 (weil es eben
> kein kanonisches Encoding gibt). Das erklärt auch, warum ich das Encoding
> z.B. in XML Starttag angeben muß, weil sonst der Leser (Das ominöse Notepad)
> nicht weiß, was er von z.B. '\xc2\x94' zu halten hat.
>
> Juhu! Oder?

Fast: bei 3) kriegst Du eine Exception, die eben genau sagt, daß das
Encoden fehlgeschlagen ist, was genau daran liegt, daß es ein
Defaultencoding gibt (per sys.getdefaultencoding() abfragbar), dieses
Defaultencoding is aber ASCII. ASCII kann aber Dein Zeichen U+0094
nicht abbilden, da der Nummer des Zeichens außerhalb von
range(128) liegt.

Ansonsten bist Du der Erleuchtung sehr nahe.

Bis demnächst,
    Walter Dörwald





More information about the Python-de mailing list