首先,ISO-8859-1
不是有效的编码声明。你想要iso-8859-1
。如果您查看文档,您可以将其称为latin_1
, iso-8859-1
, iso8859-1
, 8859
, cp819
, latin
, latin1
, or L1
,但不是ISO-8859-1
。
它看起来像是codecs.lookup
向后弯腰接受错误的输入,包括进行不区分大小写的查找。如果您追溯codecs.lookup
至_codecs.lookup
,_PyCodec_Lookup
您可以看到以下评论:
/* Convert the encoding to a normalized Python string: all
characters are converted to lower case, spaces and hyphens are
replaced with underscores. */
但是源文件解码不会经过相同的编解码器查找过程。因为它发生在编译时而不是运行时,所以没有理由这样做。(无论如何,说“它似乎有效,即使文档说它是错误的......那为什么它不能完全正确?”首先有点愚蠢。)
为了演示,如果我创建两个 Latin-1 文件:
坏代码.py:
# -*- coding: ISO-8859-1 -*-
print u"Vérifier l'affichage de cette chaîne"
好代码.py:
# -*- coding: iso-8859-1 -*-
print u"Vérifier l'affichage de cette chaîne"
第一个失败,第二个成功。
现在,为什么它在控制台时“工作”但在管道时引发异常?
好吧,当您打印到 Windows 控制台或 Unix TTY 时,Python 有一些代码可以尝试猜测要使用的正确编码。(我不确定在 Windows 上会发生什么;据我所知,它甚至可能使用 UTF-16 输出。)当您不打印到控制台/TTY 时,它不能这样做,所以您必须明确指定编码。
您可以通过查看 、 和 来了解正在发生的sys.stdout.isatty()
一些sys.stdout.encoding
事情sys.getdefaultencoding()
。以下是我在不同情况下在 Mac 上看到的内容:
- Python 2,无重定向:
True, UTF-8, ascii, Vérifier
- Python 3,无重定向:
True, UTF-8, utf-8, Vérifier
- Python 2,重定向:
False, None, ascii, UnicodeEncodeError
- Python 3,重定向:
False, UTF-8, utf-8, Vérifier
如果isatty()
,encoding
将是 TTY 的适当编码;否则,encoding
将是默认值,即 2.x 中的None
(meaning ascii
),并且 (我认为 - 我必须检查代码) 基于getdefaultencoding()
3.x 中的某些内容。这意味着如果您尝试stdout
在 2.x 中不是 TTY 时打印 Unicode,它将尝试将其编码为ascii
, strict
,如果您有非 ASCII 字符,这将失败。
如果您以某种方式知道要使用哪种编解码器,则可以在打印时通过检查isatty()
并编码到该编解码器(或者甚至是ascii
,ignore
而不是strict
,如果您愿意)手动处理此问题,而不是尝试打印 Unicode。(如果你知道你想要什么编解码器,你甚至可能希望在 3.x 中这样做——如果你试图生成 Windows-1252 文件,默认为 UTF-8 并没有太大帮助……)
那里的差异实际上与Latin-1无关。试试这个:
无码.py:
print u"V\xe9rifier l'affichage de cette cha\xeene"
print u"V\u00e9rifier l'affichage de cette cha\u00eene"
我为我的 Mac 终端获取了编码为 UTF-8 的 Unicode 字符串,并且(显然)为我的 Windows cmd 窗口获取了 Windows-1252,但异常重定向到一个文件。