为什么Python unicode字符串需要对UTF-8 BOM进行特殊处理?

为什么Python unicode字符串需要对UTF-8 BOM进行特殊处理?,python,unicode,utf-8,io,character-encoding,Python,Unicode,Utf 8,Io,Character Encoding,出于某种原因,Python在从UTF-8文件读取unicode字符串时,似乎在BOM方面存在问题。考虑以下事项: with open('test.py') as f: for line in f: print unicode(line, 'utf-8') 看起来很简单,不是吗 这就是我的想法,直到我从命令行运行它并得到: UnicodeEncodeError:“charmap”编解码器无法对字符u'\ufeff'进行编码 在位置0:字符映射到 对谷歌的简短访问表明,BOM必须

出于某种原因,Python在从UTF-8文件读取unicode字符串时,似乎在BOM方面存在问题。考虑以下事项:

with open('test.py') as f:
   for line in f:
      print unicode(line, 'utf-8')
看起来很简单,不是吗

这就是我的想法,直到我从命令行运行它并得到:

UnicodeEncodeError:“charmap”编解码器无法对字符u'\ufeff'进行编码 在位置0:字符映射到

对谷歌的简短访问表明,BOM必须手动清除:

import codecs
with open('test.py') as f:
   for line in f:
      print unicode(line.replace(codecs.BOM_UTF8, ''), 'utf-8')
这辆车开得很好。然而,我很难看出这有什么好处


上述行为背后是否有基本原理?相反,UTF-16可以无缝工作。

编码“UTF-8-sig”将代表您使用BOM签名。

您写道:

如果这些UTF-8文件中有多余的(读取:任何)BOM表。现在看看为什么在UTF-8中BOM如此愚蠢/糟糕/有害?他们实际上破坏了东西

BOM是元数据,而不是数据,UTF-8编码规范没有像UTF-16和UTF-32规范那样考虑它们。所以Python按照你的话来做,并遵循规范。这很难怪它

如果您试图使用BOM表作为文件类型幻数来指定文件的内容,那么您确实不应该这样做。您实际上应该使用更高级别的protocl来实现这些元数据目的,就像使用MIME类型一样


这只是另一个蹩脚的Windows bug,解决方法是使用替代编码
“utf-8-sig”
传递给Python

它无法对其进行编码,因为U+FEFF是无效的非字符。这是因为UTF-8文件不应该包含BOM!它们既不是必需的,也不是推荐的。Endianness对于8位代码单元没有意义。它们也把事情搞砸了,因为如果那些文件中有多余的(读取:any)BOM,你就不能再只执行
catabc>abc
。UTF-8流不应包含BOM。如果需要指定文件的内容,应该使用更高级别的protocl。这只是一个Windows错误。@tchrist-你知道,这个解释加上Josh Lee的建议会成为一个完美的答案。你的错误消息是否碰巧提到了文件名
cp437.py
?是的,“这就是问题所在,但我更感兴趣的是原因。”格林戈·苏亚夫:有趣的是,Unicode标准允许使用UTF-8格式的BOM表。参见第36页,表2-4。如果BOM不存在,有人知道这是否仍然有效吗?如果愿意,您可以将U+FEFF编码为UTF-8。你不能把它编码成拉丁语-1,这就是“charmap”对我的用法。@Josh:你说得对。我不断发现dylexic故障,把FEFF读成FFFE。对于开放式交换,FFFE是非法的。FEFF只是
零宽度不间断空间
。处理这些问题非常令人沮丧,我很想称之为Windows bug,但该标准确实允许在UTF-8文件中使用BOM。参见第36页表2-4和文本“[BOM]可能在UTF-8数据从使用BOM的其他编码形式转换或BOM用作UTF-8签名的情况下遇到。”以及
 UnicodeEncodeError: 'charmap' codec can't encode character u'\ufeff' in position 0: character maps to <undefined>
$ cat a b c > abc