Запись в файл UTF-8 на Python
-
06-09-2019 - |
Вопрос
Я действительно смущен codecs.open function
.Когда я делаю:
file = codecs.open("temp", "w", "utf-8")
file.write(codecs.BOM_UTF8)
file.close()
Это дает мне ошибку
UnicodeDecodeError:Кодек «ASCII» не может декодировать byte 0xef в позиции 0:порядковый номер вне диапазона(128)
Если я сделаю:
file = open("temp", "w")
file.write(codecs.BOM_UTF8)
file.close()
Он работает нормально.
Вопрос почему первый метод не работает?И как вставить бом?
Если второй метод является правильным, какой смысл использовать codecs.open(filename, "w", "utf-8")
?
Решение
Я считаю, что проблема в том, что codecs.BOM_UTF8
представляет собой байтовую строку, а не строку Юникода.Я подозреваю, что обработчик файла пытается угадать, что вы на самом деле имеете в виду, основываясь на том, что «я должен был писать Unicode в виде текста в кодировке UTF-8, но вы дали мне строку байтов!»
Попробуйте написать строку Unicode для обозначения порядка байтов (т.Unicode U+FEFF) напрямую, так что файл просто кодирует это как UTF-8:
import codecs
file = codecs.open("lol", "w", "utf-8")
file.write(u'\ufeff')
file.close()
(Кажется, это дает правильный ответ — файл с байтами EF BB BF.)
РЕДАКТИРОВАТЬ:С.Лотта предположение использования «utf-8-sig», поскольку кодировка лучше, чем явное написание спецификации самостоятельно, но я оставлю этот ответ здесь, поскольку он объясняет, что шло не так раньше.
Другие советы
Прочтите следующее: http://docs.python.org/library/codecs.html#module-encodings.utf_8_sig
Сделай это
with codecs.open("test_output", "w", "utf-8-sig") as temp:
temp.write("hi mom\n")
temp.write(u"This has ♭")
Полученный файл имеет формат UTF-8 с ожидаемой спецификацией.
@S-Lott дает правильную процедуру, но расширяет Юникод проблемы, Питон переводчик может дать больше информации.
Джон Скит прав (необычно) насчет codecs
модуль — он содержит строки байтов:
>>> import codecs
>>> codecs.BOM
'\xff\xfe'
>>> codecs.BOM_UTF8
'\xef\xbb\xbf'
>>>
Выбрав еще одну гниду, BOM
имеет стандарт Юникод имя, и его можно ввести как:
>>> bom= u"\N{ZERO WIDTH NO-BREAK SPACE}"
>>> bom
u'\ufeff'
Он также доступен через unicodedata
:
>>> import unicodedata
>>> unicodedata.lookup('ZERO WIDTH NO-BREAK SPACE')
u'\ufeff'
>>>
Я использую команду file *nix для преобразования неизвестного файла кодировки в файл 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()