Почему строки юникода Python требуют специальной обработки для спецификации UTF-8?

По какой-то причине у Python возникают проблемы с BOM при чтении строк юникода из файла UTF-8. Рассмотрим следующее:

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

Кажется прямым, не так ли?

Это то, что я думал, пока не запустил его из командной строки и не получил:

UnicodeEncodeError: кодек 'charmap' не может кодировать символ u '\ ufeff' в позиции 0: символьные карты на <undefined>

Краткий обзор Google показал, что спецификация должна быть очищена вручную:

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

Это работает отлично. Однако я изо всех сил стараюсь увидеть в этом заслугу.

Существует ли обоснование вышеописанного поведения?. Напротив, UTF-16 работает без проблем.

Ответы

Ответ 1

Кодирование 'utf-8-sig' будет использовать подпись BOM от вашего имени.

Ответ 2

Вы писали:

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

Когда вы указываете кодировку "utf-8" в Python, она берет вас на ваше слово. Файлы UTF-8 arent должны содержать в них спецификацию. Они не требуются и не рекомендуются. Endianness не имеет смысла с 8-битными блоками кода.

Спецификации винта вверх, тоже, потому что вы больше не можете просто делать:

$ cat a b c > abc 

если эти файлы UTF-8 имеют посторонние (чтение: любые) спецификации в них. Посмотрите теперь, почему спецификации являются настолько глупыми/вредными/вредными в UTF-8? Они действительно нарушают вещи.

Спецификация - это метаданные, а не данные, а спецификация кодирования UTF-8 не учитывает их, как это делают спецификации UTF-16 и UTF-32. Итак, Python взял вас на ваше слово и последовал спецификации. Трудно обвинить его в этом.

Если вы пытаетесь использовать спецификацию в качестве магического номера типа файлов, чтобы указать содержимое файла, вы действительно не должны этого делать. Вы действительно должны использовать прототип более высокого уровня для этих целей метаданных, как и с типом MIME.

Это просто еще одна ошибка хромой Windows, обходной путь для которой заключается в использовании альтернативной кодировки "utf-8-sig" для передачи на Python.