2012-09-08 10 views
5

edito tres archivos que tienen el mismo contenido "你" (es you en inglés) en tres formas diferentes - gbk \ utf-8 \ ucs-2 con gedit llamado "ok1, ok2, ok3 ".unicode endian me desconcertó

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

de hecho f3 es '\ x60 \ X4F', pero el resultado siguiente me confundió

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

por qué sólo hay un problema endian en UCS-2 (o decir Unicode), no en utf-8, no en gbk?

Respuesta

5

UTF-8 y GBK almacenar datos en una secuencia de bytes. Está fuertemente definido qué valor de bytes viene después de que en estas codificaciones. Este orden de bytes no cambia con la arquitectura utilizada en codificación, transmisión o decodificación.

Por otro lado, UCS-2 o el nuevo 16 UTF- datos tiendas en las secuencias de 2-bytes. El orden de los bytes individuales dentro de estos tokens de 2 bytes es endianness y depende de la arquitectura de la máquina subyacente. Los sistemas deben tener un acuerdo sobre cómo identificar la endianidad de los tokens antes de comunicarse con los datos codificados en UCS-2.

En su caso, el punto Unicode U + 4F60 se codifica en UCS-2 como una sola 2-byte contador 0x4F60. Como su máquina coloca el byte menos significativo antes que el más significativo en la alineación de memoria, la secuencia ('0x60', '0x4F') se ha colocado en el archivo. Por lo tanto, la lectura del archivo dará los bytes en este orden.

Python todavía puede decodificar estos datos correctamente, ya que leerá los bytes en el orden correcto antes de formar el token de 2 bytes:

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

Dado que su máquina coloca el byte menos significativo antes que el más significativo en la alineación de memoria, la secuencia ('0x60', '0x4F') se ha colocado en el archivo. Por lo tanto, la lectura del archivo producirá los bytes en este orden. ¿Por qué en mi máquina, f1 no es '\ xe3 \ xc4 \ n'? f2 no ​​es f2 '\ xbd \ xe4 \ xa0 \ n' –

+0

@Dd Pp: Porque al escribir un archivo utf-8, gedit coloca los bytes * uno por uno *. Sin embargo, al escribir un archivo codificado ucs-2, gedit pone los bytes * dos por dos *. El orden en bytes depende de la endiancia solo en este último caso. –

3

Endian-dad sólo se aplica a las palabras de múltiples bytes, pero UTF-8 usa unidades de 8 bits para codificar información (eso es lo que representa el 8 en el nombre). Nunca existe la cuestión de la confusión de ordenar allí.

A veces puede necesitar más de una de esas unidades para codificar información, pero se consideran distintas. La letra A es un byte, 0x41, por ejemplo. Cuando tiene que codificar un carácter con más bytes, usa un byte indicador adelantado, seguido de bytes de continuación adicionales para capturar toda la información necesaria para ese personaje. Lógicamente, estas son unidades distintas.

GBK utiliza un esquema similar; los personajes usan unidades de 1 byte, y al igual que UTF-8, se puede usar un segundo byte para algunos de los caracteres.

UCS-2 (y su sucesor, UTF-16) por otro lado, es un formato de 2 bytes. Codifica información en unidades de 16 bits, y esos 16 bits siempre van juntos. Los 2 bytes en esa unidad se combinan lógicamente, y las arquitecturas modernas los tratan como una sola unidad, y así han tomado una decisión en qué orden se almacenan. Ahí es donde entra la endianess, el orden de los 2 bytes en una unidad depende de la arquitectura. En tu arquitectura, los bytes se ordenan usando little-endianess, lo que significa que el byte 'más pequeño' va primero. Esta es la razón por la cual el byte 0x4F viene antes del byte 0x60 en su archivo.

Tenga en cuenta que python puede leer ya sea grande o poco endian UTF-16 bien; Usted puede escoger el endianess explícitamente si no hay un carácter de indicador al comienzo (el byte de marca de orden, o 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' 

En este último ejemplo, los bytes se han invertido, y se decodifica como big-endian.

Cuestiones relacionadas