2012-09-08 99 views
5

我編輯了三個文件,它們有三個不同的形式 - 「gbk \ utf-8 \ ucs-2」,其中gedit命名爲「ok1,ok2,ok3」,它有相同的內容「你」(英文爲you) 」。unicode endian困惑我

>>> 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' 

其實f3是 '\ X60 \ x4f', 但下面的輸出困惑我

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

爲什麼只出現在UCS-2端的問題(或者說Unicode)的,而不是在utf-8,不在gbk中?

回答

5

UTF-8 and GBK以字節序列存儲數據。它強烈定義了在這些編碼之後的哪個字節值。該字節順序不隨編碼,傳輸或解碼中使用的體系結構而改變。

在另一方面,UCS-2或新UTF-16商店中的2個字節的序列的數據。這些2字節標記內的單個字節的順序是排列順序,它取決於底層的機器體系結構。系統必須就如何識別令牌的字節順序達成一致,然後才能與編碼爲UCS-2的數據進行通信。

在你的情況下,Unicode點U + 4F60被編碼爲UCS-2作爲單個雙字節標記0x4F60。由於您的機器在內存對齊中的最重要字節之前放置了最低有效字節,因此序列('0x60', '0x4F')已被放入該文件中。因此,文件讀取將按此順序產生字節。

的Python仍然可以正確地解碼該數據,因爲它會形成2個字節的令牌之前讀取在正確的順序中的字節:

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

由於您的機器在內存對齊中的最重要字節之前放置了最低有效字節,所以序列('0x60','0x4F')已被放入文件中。因此,文件讀取將按此順序產生字節。爲什麼在我的機器中,f1不是'\ xe3 \ xc4 \ n'? f2不是f2'\ xbd \ xe4 \ xa0 \ n' –

+0

@Dd Pp:因爲編寫utf-8文件時,gedit會將字節*逐個*。但是,在編寫ucs-2編碼文件時,gedit會將字節*兩乘二*。字節內的順序僅在後一種情況下依賴於字節順序。 –

3

字節序只適用於多字節字,但UTF-8使用8位單位來編碼信息(這就是名字中的8代表)。在那裏訂購從來沒有混淆的問題。

有時它可能需要多個這些單位來編碼信息,但它們被認爲是不同的。例如,字母A是一個字節,0x41。當它需要用更多的字節對一個字符進行編碼時,它使用一個領先的指示符字節,然後是額外的連續字節來捕獲該字符所需的所有信息。從邏輯上講,這些是不同的單位。

GBK使用類似的方案;字符使用1個字節的單位,就像UTF-8一樣,第二個字節可以用於某些字符。另一方面,UCS-2(以及它的後繼者,UTF-16)是一個2字節的格式。它以16位爲單位對信息進行編碼,並且這16位總是一起進行。該單元中的2個字節在邏輯上屬於一個整體,現代體系結構將這些單元視爲一個單元,從而根據它們的存儲順序做出決定。這就是endianess進來的地方,單元中2個字節的順序依賴於體系結構。在你的體系結構中,字節使用little-endianess進行排序,這意味着「較小」字節首先排列。這就是爲什麼0x4F字節出現在文件中的0x60字節之前。

請注意,python可以讀取大或小端UTF-16就好;你可以挑選字節序明確如果在開始時無指示字符(字節順序標記或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' 

在後一個例子字節已經發生了逆轉,並作爲解碼大端。