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

Sau*_*aul 14 python unicode io utf-8 character-encoding

出于某种原因,当从UTF-8文件中读取unicode字符串时,Python似乎遇到了BOM问题.考虑以下:

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

看起来很直白,不是吗?

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

UnicodeEncodeError:'charmap'编解码器无法对位置0中的字符u'\ ufeff'进行编码:字符映射到 <undefined>

对Google的简短访问显示,必须手动清除 BOM :

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

这个运行正常.但是我很难看到这方面的任何优点.

上述行为背后有理由吗?相比之下,UTF-16无缝工作.

Jos*_*Lee 28

该'utf-8-sig'编码将消耗代表您的BOM签名.

  • 根据定义,UTF8没有字节顺序标记. (3认同)
  • @Gringo Suave:有趣的是Unicode标准确实允许使用UTF-8的BOM.请参见第26页的http://www.unicode.org/versions/Unicode5.0.0/ch02.pdf,表2-4. (3认同)

tch*_*ist 13

你写了:

 UnicodeEncodeError: 'charmap' codec can't encode character u'\ufeff' in position 0: character maps to <undefined>
Run Code Online (Sandbox Code Playgroud)

当你"utf-8"在Python中指定编码时,它会引导你.UTF-8文件不应包含BOM.它们既不是必需也不是推荐.对于8位代码单元,字节顺序没有意义.

BOM也搞砸了,因为你不能再做了:

$ cat a b c > abc 
Run Code Online (Sandbox Code Playgroud)

如果这些UTF-8文件中包含无关(读取:任何)BOM.现在看看为什么BOMs在UTF-8中如此愚蠢/糟糕/有害?他们实际上打破了一切

BOM是元数据,而不是数据,UTF-8编码规范不像UTF-16和UTF-32规范那样允许它们.所以Python带你到你的话,遵循规范.很难为此归咎于此.

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

这只是另一个蹩脚的Windows错误,其解决方法是使用备用编码"utf-8-sig"传递给Python.

  • 如果您愿意,可以将U + FEFF编码为UTF-8.你不能把它编码成latin-1,这就是'charmap'对我的用法. (2认同)
  • @Josh:你是对的.我不断出现视觉障碍并将FEFF作为FFFE读取.这是FFFE,这对于开放式交换来说是非法的.FEFF只是"ZERO WIDTH NO-BREAK SPACE". (2认同)
  • 处理这些问题非常令人沮丧,我很乐意将其称为Windows错误,但该标准确实允许使用UTF-8文件中的BOM.请参见http://unicode.org/versions/Unicode5.0.0/ch02.pdf第36页,表2-4,在从其他编码形式转换UTF-8数据的上下文中可能遇到文本"_ [BOM]使用BOM或将BOM用作UTF-8签名._"和http://en.wikipedia.org/wiki/Byte_order_mark和[Re:pre-HTML5和2012 - 07年来自Asmus Freytag的BOM -13(Unicode邮件列表存档)](http://www.unicode.org/mail-arch/unicode-ml/y2012-m07/0268.html) (2认同)