2012-09-08 4 views
5

Ich bearbeite drei Dateien, die gleichen Inhalt haben "你" (ist you in Englisch) in drei verschiedenen Formen - gbk \ utf-8 \ ucs-2 mit gedit namens "ok1, ok2, ok3 ".Unicode Endian verwirrt mich

>>> f1 = open('ok1', 'rb').read() 
>>> f2 = open('ok2', 'rb').read() 
>>> f3 = open('ok3', 'rb').read() 
>>> f1 
'\xc4\xe3\n' 
>>> f2 
'\xe4\xbd\xa0\n' 
>>> f3 
'`O\n\x00' 
>>> hex(ord("`")) 
'0x60' 
>>> hex(ord("O")) 
'0x4f' 

in der Tat f3 '\ x60 \ x4f', aber die folgende Ausgabe verwirrt mich

>>> '\xe4\xbd\xa0'.decode("utf-8") 
u'\u4f60' 
>>> '\xc4\xe3'.decode("gbk") 
u'\u4f60' 
>>> 

, warum es nur Endian-Problem in UCS-2 (oder sagen Unicode) ist, nicht in utf-8, nicht in gbk?

Antwort

5

UTF-8 und GBK Daten in einer Bytefolge speichern. Es ist fest definiert, welcher Byte-Wert nach diesen Codierungen kommt. Diese Byte-Reihenfolge ändert sich nicht mit der Architektur, die beim Codieren, Senden oder Decodieren verwendet wird.

Auf der anderen Seite, UCS-2 oder die neuenUTF-16 speichern Daten in Sequenzen von 2-Byte. Die Reihenfolge der einzelnen Bytes innerhalb dieser 2-Byte-Token ist die Endianness und es hängt von der zugrunde liegenden Rechnerarchitektur ab. Systeme müssen eine Übereinstimmung darüber haben, wie die Endianz von Tokens identifiziert werden kann, bevor sie mit Daten kommunizieren, die in UCS-2 codiert sind.

In Ihrem Fall wird der Unicode-Punkt U + 4F60 in UCS-2 als ein einzelnes 2-Byte-Token 0x4F60 codiert. Da Ihr Computer das niedrigstwertige Byte vor dem höchstwertigen Byte in die Speicherausrichtung einfügt, wurde die Sequenz ('0x60', '0x4F') in die Datei eingefügt. Daher werden beim Lesen der Datei die Bytes in dieser Reihenfolge ausgegeben.

Python kann immer noch diese Daten entschlüsselt korrekt, da es das Bytes in der richtigen Reihenfolge gelesen werden, bevor die 2-Byte-Token bilden:

>>> '`O\n\x00'.decode('utf-16') 
u'\u4f60\n' 
+0

Da Ihr Computer das niedrigstwertige Byte vor dem höchstwertigen Byte in die Speicherausrichtung einfügt, wurde die Sequenz ('0x60', '0x4F') in die Datei geschrieben. Die Datei liest also die Bytes in dieser Reihenfolge. Warum ist f1 in meiner Maschine nicht '\ xe3 \ xc4 \ n' ?? f2 ist nicht f2 '\ xbd \ xe4 \ xa0 \ n' –

+0

@Dd Pp: Weil gedit beim Schreiben einer utf-8-Datei Bytes * eins nach dem anderen * schreibt. Beim Schreiben einer codierten Datei mit ucs-2 werden jedoch die Bytes * zwei mal zwei * eingegeben. Die Reihenfolge innerhalb von Bytes hängt nur im letzteren Fall von der Endianz ab. –

3

Endian-ness gilt nur für Multi-Byte-Worte, aber UTF-8 benutzt Einheiten von 8 Bits, um Informationen zu kodieren (dafür steht die 8 im Namen). Es gibt nie die Frage der Verwirrung der Anordnung dort.

Manchmal benötigt es möglicherweise mehr als eine dieser Einheiten, um Informationen zu kodieren, aber sie werden als verschieden angesehen. Der Buchstabe A ist ein Byte, beispielsweise 0x41. Wenn ein Zeichen mit mehreren Bytes codiert werden muss, wird ein vorangestelltes Indikatorbyte gefolgt von zusätzlichen Fortsetzungsbytes verwendet, um alle für dieses Zeichen erforderlichen Informationen zu erfassen. Logischerweise sind dies unterschiedliche Einheiten.

GBK verwendet ein ähnliches Schema; Zeichen verwenden Einheiten von 1 Byte und genau wie UTF-8 kann ein zweites Byte für einige der Zeichen verwendet werden.

UCS-2 (und sein Nachfolger, UTF-16) hingegen ist ein 2-Byte-Format. Es codiert Informationen in Einheiten von 16 Bits, und diese 16 Bits gehören immer zusammen. Die 2 Bytes in dieser Einheit gehören logisch zusammen, und moderne Architekturen behandeln diese als eine Einheit und haben somit eine Entscheidung getroffen, in welcher Reihenfolge sie gespeichert sind. Hier kommt die Endianität ins Spiel, die Reihenfolge der 2 Bytes in einer Einheit ist architekturabhängig. In Ihre Architektur sind die Bytes mit Little-Endianess geordnet, was bedeutet, dass das "kleinere" Byte zuerst geht. Deshalb kommt das 0x4F Byte vor dem 0x60 Byte in Ihrer Datei.

Beachten Sie, dass Python entweder große oder kleine Endian UTF-16 gut lesen kann; Sie können die Endianess explizit auswählen, wenn kein Indikator Zeichen am Anfang (die Byte Order Mark, oder BOM):

>>> '`O\n\x00'.decode('utf-16') 
u'\u4f60\n' 
>>> '`O\n\x00'.decode('utf-16-le') 
u'\u4f60\n' 
>>> 'O`\x00\n'.decode('utf-16-be') 
u'\u4f60\n' 

Im letzteren Beispiel der Bytes umgekehrt worden war, und decodierten als Big-Endian.

Verwandte Themen