2011-09-01 14 views
14

Por alguna razón, Python parece estar teniendo problemas con BOM al leer cadenas de Unicode de un archivo UTF-8. Considere lo siguiente:¿Por qué las cadenas Unicode de Python requieren un tratamiento especial para la lista de materiales UTF-8?

with open('test.py') as f: 
    for line in f: 
     print unicode(line, 'utf-8') 

Parece sencillo, ¿no?

Eso es lo que pensaba hasta que me encontré con él desde la línea de comandos y tengo:

UnicodeEncodeError: 'charmap' codec can't encode character u'\ufeff' in position 0: character maps to <undefined>

Una breve visita a Google reveló que la lista de materiales tiene que ser borrar manualmente:

import codecs 
with open('test.py') as f: 
    for line in f: 
     print unicode(line.replace(codecs.BOM_UTF8, ''), 'utf-8') 

Ésta funciona bien. Sin embargo, estoy luchando para ver algún mérito en esto.

¿Hay alguna razón detrás del comportamiento descrito anteriormente? Por el contrario, UTF-16 funciona sin problemas.

+4

No puede codificarlo porque U + FEFF es un carácter no válido. ¡Se supone que los archivos UTF-8 * no deben contener una lista de materiales en ellos! No son requeridos ni recomendados. Endianness no tiene sentido con unidades de código de 8 bits. También arruinan las cosas, porque ya no puedes hacer 'cat a b c> abc' si esos archivos tienen BOMs extraños (léase: * any *). Las transmisiones UTF-8 no deben contener una lista de materiales. Si necesita especificar el contenido del archivo, se supone que debe usar un prototipo de nivel superior. Esto es solo un error de Windows. – tchrist

+0

@tchrist - Sabes, esta explicación en combinación con la sugerencia de Josh Lee sería una respuesta perfecta. – Saul

+0

Ok, añadido.Espero que eso funcione – tchrist

Respuesta

28

La codificación 'utf-8-sig' consumirá la firma BOM en su nombre.

+0

Sí, esa es la solución, pero estaba más interesado en el por qué. – Saul

+3

UTF8 no tiene marca de orden de bytes por definición. –

+3

@Gringo Suave: Lo curioso es que el estándar Unicode permite una lista de materiales en UTF-8. Ver http://www.unicode.org/versions/Unicode5.0.0/ch02.pdf página 36, ​​tabla 2-4. – Saul

13

Usted escribió:

UnicodeEncodeError: 'charmap' codec can't encode character u'\ufeff' in position 0: character maps to <undefined> 

Cuando se especifica la codificación "utf-8" en Python, que le lleva a su palabra. Los archivos UTF-8 no se supone que contengan una lista de materiales en ellos. No son requeridos ni recomendados. Endianness no tiene sentido con unidades de código de 8 bits.

listas de materiales enredar las cosas, también, porque ya no se puede simplemente hacer:

$ cat a b c > abc 

si esos ficheros UTF-8 tienen extraños (es decir: las listas de materiales) en ellos. Vea ahora por qué las listas de materiales son tan estúpidas/malas/dañinas en UTF-8? Ellos realmente rompen cosas.

Una BOM son metadatos, no datos, y la especificación de codificación UTF-8 no tiene en cuenta la forma en que lo hacen las especificaciones UTF-16 y UTF-32. Entonces Python lo tomó en cuenta y siguió las especificaciones. Es difícil culparlo por eso.

Si está tratando de utilizar la lista de materiales como un número mágico de tipo de archivo para especificar el contenido del archivo, realmente no debería estar haciendo eso. Se supone que debes usar un prototipo de nivel superior para estos metadatos, tal como lo harías con un tipo MIME.

Esto es solo otro error cojo de Windows, la solución para la cual es usar la codificación alternativa "utf-8-sig" para pasar a Python.

+2

Puede codificar U + FEFF en UTF-8 si lo desea. No puedes codificarlo en latin-1, que es lo que 'charmap' usa para mí. –

+2

@Josh: tienes razón. Sigo teniendo mal funcionamiento dílexico y leyendo FEFF como FFFE. Es FFFE que es ilegal para el intercambio abierto. FEFF es simplemente 'ESPACIO SIN CRONOMETRO DE ANCHO CERO '. – tchrist

+2

Es muy frustrante lidiar con esto, y me gustaría llamar a esto un error de Windows, pero el estándar sí permite listas de materiales en archivos UTF-8. Consulte http://unicode.org/versions/Unicode5.0.0/ch02.pdf página 36, ​​tabla 2-4 y encontrará el texto "_ [a BOM] en contextos donde los datos UTF-8 se convierten de otras codificaciones formularios que usan una lista de materiales o donde la lista de materiales se utiliza como firma UTF-8 ._ "y http://en.wikipedia.org/wiki/Byte_order_mark y [Re: pre-HTML5 y la lista de materiales de Asmus Freytag en 2012 -07-13 (Archivo de lista de correo Unicode)] (http://www.unicode.org/mail-arch/unicode-ml/y2012-m07/0268.html) – nealmcb

Cuestiones relacionadas