Escribir en el archivo UTF-8 en Python


Estoy realmente confundido con el codecs.open function. Cuando lo hago:

file = codecs.open("temp", "w", "utf-8")
file.write(codecs.BOM_UTF8)
file.close()

Me da el error

UnicodeDecodeError: el códec 'ascii' no puede decodificar el byte 0xef en posición 0: ordinal no dentro del rango(128)

Si lo hago:

file = open("temp", "w")
file.write(codecs.BOM_UTF8)
file.close()

Funciona bien.

Pregunta ¿Por qué falla el primer método? ¿Y cómo inserto la lista de materiales?

Si el segundo método es la forma correcta de hacerlo, ¿cuál es el punto de usar codecs.open(filename, "w", "utf-8")?

Author: guaka, 2009-06-01

4 answers

Creo que el problema es que codecs.BOM_UTF8 es una cadena de bytes, no una cadena Unicode. Sospecho que el controlador de archivos está tratando de adivinar lo que realmente quiere decir basado en " Estoy destinado a escribir Unicode como texto codificado en UTF-8, pero me has dado una cadena de bytes!"

Intente escribir la cadena Unicode para la marca de orden de bytes (es decir, Unicode U+FEFF) directamente, de modo que el archivo simplemente lo codifique como UTF-8:

import codecs

file = codecs.open("lol", "w", "utf-8")
file.write(u'\ufeff')
file.close()

(Que parece dar la respuesta correcta - un archivo con bytes EF BB BF.)

EDITAR: La sugerencia de S. Lott de usar "utf-8-sig" como codificación es mejor que escribir explícitamente la lista de materiales tú mismo, pero dejaré esta respuesta aquí, ya que explica lo que estaba pasando mal antes.

 226
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-17 19:24:56

Léase lo siguiente: http://docs.python.org/library/codecs.html#module-encodings.utf_8_sig

Haga esto

with codecs.open("test_output", "w", "utf-8-sig") as temp:
    temp.write("hi mom\n")
    temp.write(u"This has ♭")

El archivo resultante es UTF-8 con la lista de materiales esperada.

 152
Author: S.Lott,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-14 02:31:25

@S-Lott da el procedimiento correcto, pero expandiendo los problemas Unicode , el intérprete Python puede proporcionar más información.

Jon Skeet tiene razón (inusual) sobre el codecs módulo-contiene cadenas de bytes:

>>> import codecs
>>> codecs.BOM
'\xff\xfe'
>>> codecs.BOM_UTF8
'\xef\xbb\xbf'
>>> 

Seleccionando otro nit, el BOM tiene un nombre estándar Unicode , y se puede ingresar como:

>>> bom= u"\N{ZERO WIDTH NO-BREAK SPACE}"
>>> bom
u'\ufeff'

También es accesible a través de unicodedata:

>>> import unicodedata
>>> unicodedata.lookup('ZERO WIDTH NO-BREAK SPACE')
u'\ufeff'
>>> 
 10
Author: gimel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-01 17:10:17

Uso el comando file * nix para convertir un archivo de charset desconocido en un archivo utf-8

# -*- encoding: utf-8 -*-

# converting a unknown formatting file in utf-8

import codecs
import commands

file_location = "jumper.sub"
file_encoding = commands.getoutput('file -b --mime-encoding %s' % file_location)

file_stream = codecs.open(file_location, 'r', file_encoding)
file_output = codecs.open(file_location+"b", 'w', 'utf-8')

for l in file_stream:
    file_output.write(l)

file_stream.close()
file_output.close()
 5
Author: Ricardo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-08 20:35:11