Écrire dans un fichier UTF-8 en Python
-
06-09-2019 - |
Question
Je suis vraiment confondu avec le codecs.open function
. Quand je fais:
file = codecs.open("temp", "w", "utf-8")
file.write(codecs.BOM_UTF8)
file.close()
Il me donne l'erreur
UnicodeDecodeError: codec 'ascii' ne peut pas décoder octet 0xEF en position 0: ordinal dans la plage (128)
Si je fais:
file = open("temp", "w")
file.write(codecs.BOM_UTF8)
file.close()
Il fonctionne très bien.
Question est pourquoi la première méthode a échoué? Et comment puis-je insérer le bom?
Si la deuxième méthode est la bonne façon de le faire, ce que le point d'utiliser codecs.open(filename, "w", "utf-8")
?
La solution
Je crois que le problème est que codecs.BOM_UTF8
est une chaîne d'octets, pas une chaîne Unicode. Je soupçonne que le gestionnaire de fichiers tente de deviner ce que vous voulez vraiment dire basé sur « Je suis censé être écrit sous forme de texte Unicode UTF-8 codé, mais vous me avez donné une chaîne d'octets! »
Essayez d'écrire la chaîne de caractères Unicode pour la marque d'ordre d'octet (à savoir Unicode U + FEFF) directement, de sorte que le fichier code juste que UTF-8:
import codecs
file = codecs.open("lol", "w", "utf-8")
file.write(u'\ufeff')
file.close()
(Cela semble donner la bonne réponse -. Un fichier avec des octets EF BB BF)
EDIT: S. Lott suggestion d'utiliser "utf-8-sig" comme l'encodage est un meilleur que écrire explicitement la nomenclature vous-même, mais je vais laisser cette réponse ici car il explique ce qui se passait mal avant.
Autres conseils
Lisez ce qui suit: http://docs.python.org/ bibliothèque / codecs.html # module encodings.utf_8_sig
Pour ce faire,
with codecs.open("test_output", "w", "utf-8-sig") as temp:
temp.write("hi mom\n")
temp.write(u"This has ♭")
Le fichier résultant est UTF-8 avec la nomenclature attendue.
@ S-Lott donne la bonne procédure, mais en expansion sur les Unicode questions, l'interprète Python peut fournir plus d'idées.
Jon Skeet est juste (inhabituel) sur le codecs
Module - il contient des chaînes d'octets:
>>> import codecs
>>> codecs.BOM
'\xff\xfe'
>>> codecs.BOM_UTF8
'\xef\xbb\xbf'
>>>
Choisir une autre petite bête, le BOM
a une norme Unicode nom, et il peut être entré comme:
>>> bom= u"\N{ZERO WIDTH NO-BREAK SPACE}"
>>> bom
u'\ufeff'
Il est également accessible via unicodedata
:
>>> import unicodedata
>>> unicodedata.lookup('ZERO WIDTH NO-BREAK SPACE')
u'\ufeff'
>>>
J'utilise le fichier * commande nix pour convertir un fichier charset inconnu dans un fichier 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()