为什么在控制台和管道中打印unicode字符串时python的行为不一样?

2024-06-16 09:47:25 发布

您现在位置:Python中文网/ 问答频道 /正文

经过几次测试,我设法将故障限制在最低限度测试.py以下脚本:

# -*- coding: iso-8859-1 -*-
print u"Vérifier l'affichage de cette chaîne"

注:测试.py在ISO-8859-1(即拉丁语-1)中编码,即“é”等于“\xe9”,“î”等于“\xee”

^{pr2}$

问题是:

为什么python在打印unicode字符串时的行为不一样,不管它的标准输出是到控制台还是被重定向或通过管道传输到其他地方?在


Tags: py脚本deiso故障neprintcoding
2条回答

首先,ISO-8859-1不是有效的编码声明。你想要iso-8859-1。如果您看一下the docs,您可以将其称为latin_1iso-8859-1iso8859-18859cp819latinlatin1、或{},但不能叫{}。在

看起来codecs.lookup向后弯曲以接受错误的输入,包括执行不区分大小写的查找。如果跟踪^{}到{a3}到^{},则可以看到以下注释:

/* Convert the encoding to a normalized Python string: all
   characters are converted to lower case, spaces and hyphens are
   replaced with underscores. */

但是源文件解码并没有经过相同的编解码器查找过程。因为它发生在编译时而不是运行时,所以没有理由这么做。(无论如何,他会说“虽然医生说这是错误的,但它似乎起作用了……那么为什么它不能完全起作用?”一开始就有点傻。)

为了演示,如果我创建两个拉丁语-1文件:

在坏代码.py公司名称:

^{pr2}$

在好代码.py公司名称:

# -*- coding: iso-8859-1 -*-
print u"Vérifier l'affichage de cette chaîne"

第一个失败了,第二个成功了。在

现在,为什么它在控制台时“工作”,而在管道传输时引发异常?在

好吧,当您打印到Windows控制台或unixtty时,Python有一些代码可以尝试猜测要使用的正确编码。(我不知道在Windows上会发生什么;据我所知,它甚至可能使用UTF-16输出。)当您不打印到控制台/TTY时,它不能这样做,所以您必须显式地指定编码。在

您可以通过查看sys.stdout.isatty()sys.stdout.encoding、和{}来了解发生了什么。以下是我在Mac电脑上看到的不同情况:

  • Python2,无重定向:True, UTF-8, ascii, Vérifier
  • Python3,无重定向:True, UTF-8, utf-8, Vérifier
  • Python2,重定向:False, None, ascii, UnicodeEncodeError
  • Python3,重定向:False, UTF-8, utf-8, Vérifier

如果isatty()encoding将是TTY的适当编码;否则,encoding将是默认值,在2.x中是None(意思是ascii),并且(我想-我必须检查代码)基于3.x中的getdefaultencoding()的内容。这意味着如果您试图打印Unicode,而stdout不是2.x中的TTY,它将尝试将其编码为asciistrict,如果您有非ASCII字符,则将失败。在

如果您不知何故知道要使用哪个编解码器,则可以通过检查isatty()并对该编解码器进行编码(如果愿意,甚至可以选择asciiignore而不是{})来手动处理,而不是尝试打印Unicode。(如果你知道你想要什么样的编解码器,即使在3.x版本中也可以这么做,如果你想生成,比如说,Windows-1252文件,那么默认为UTF-8也没有太大帮助…)

这里的区别实际上与拉丁语-1无关。试试这个:

在无代码.py公司名称:

print u"V\xe9rifier l'affichage de cette cha\xeene"
print u"V\u00e9rifier l'affichage de cette cha\u00eene"

对于我的Mac终端,我将Unicode字符串编码为UTF-8,并(显然)将Windows-1252编码到windowscmd窗口,但重定向到文件时出现异常。在

因为我在这里寻找“不要太聪明”切换到python的print()并且答案提供了只读变量的提示,下面是“让python相信stdout可以处理utf-8”的片段:

import sys, codecs

# somewhere in the function you need it or global main():
sys.stdout = codecs.open('/dev/stdout', encoding='utf-8', mode='w', errors='strict')

现在,python不关心它是tty、tee(1)、文件重定向还是cat(1)。在

相关问题 更多 >