运行代码时:
#! /usr/bin/env python
# -*- coding: UTF-8 -*-
import xml.etree.ElementTree as ET
print ET.fromstring('<?xml version="1.0" encoding="UTF-8" standalone="yes"?><root><road>vägen</road></root>').find('road').text
生成预期的输出vägen
,但是如果将其汇总到wc -l
,我会得到一个UnicodeEncodeError,例如(TEerr.py包含上面给出的代码片段):
:~> ETerr.py | wc -l
Traceback (most recent call last):
File "./ETerr.py", line 5, in <module>
print ET.fromstring('<?xml version="1.0" encoding="UTF-8" standalone="yes"?><root><road>vägen</road></root>').find('road').text
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe4' in position 1: ordinal not in range(128)
0
:~>
如果输出是否通过管道传输,代码如何表现不同?如何修复它以使其不受管理。
请注意,上面的代码片段仅用于演示尽可能少的代码问题,在我需要解决问题的实际脚本中使用urllib
检索xml因此我几乎没有控制其格式。
答案 0 :(得分:0)
首先,我要指出这不是Python 3中的一个问题,并且修复它实际上是首先值得对该语言进行兼容性破坏更改的原因之一。但我认为你有充分的理由使用Python 2,而不能只升级。
这里的近因(假设您在POSIX平台上使用Python 2.7--在旧的2.x上更复杂,在Windows上)是sys.stdout.encoding
的值。当你启动解释器时,它会相当于这个伪代码:
if isatty(stdoutfd):
sys.stdout.encoding = parse_locale(os.environ('LC_CTYPE'))
else:
sys.stdout.encoding = None
每当你write
到一个文件,包括sys.stdout
,包括print
语句中隐含的文件时,它就会执行以下操作:
if isinstance(s, unicode):
if self.encoding:
s = s.encode(self.encoding)
else:
s = s.encode(sys.getdefaultencoding())
实际代码执行标准POSIX的东西,寻找像LANG
这样的后备,并在某些情况下为Mac OS X等硬编码回退到UTF-8,但这已足够接近。
此文件使用的编码。将Unicode字符串写入文件时,将使用此编码将它们转换为字节字符串。此外,当文件连接到终端时,该属性给出终端可能使用的编码(如果用户错误配置了终端,该信息可能是不正确的)。该属性是只读的,可能不存在于所有类文件对象上。它也可能是
None
,在这种情况下,文件使用系统默认编码来转换Unicode字符串。
要验证这是您的问题,请尝试以下操作:
$ python -c 'print __import__("sys").stdout.encoding'
UTF-8
$ python -c 'print __import__("sys").stdout.encoding' | cat
None
更确定这是问题所在:
$ PYTHONIOENCODING=Latin-1 python -c 'print __import__("sys").stdout.encoding'
Latin-1
$ PYTHONIOENCODING=Latin-1 python -c 'print __import__("sys").stdout.encoding' | cat
Latin-1
那么,你如何解决这个问题?
嗯,显而易见的方法是升级到Python 3.6,在这两种情况下你都会得到UTF-8,但我认为你使用Python 2.7是有原因的,并且不能轻易改变它。 / p>
正确的解决方案实际上非常复杂。但是,如果你想要一个适用于你的系统的快速和肮脏的解决方案,以及大多数当前使用标准Python 2.7设置的Linux和Mac系统(尽管对于较旧的Linux系统可能是灾难性的错误,旧的Python 2.x版本,并且很奇怪设置),你可以:
PYTHONIOENCODING
以覆盖检测并强制使用UTF-8。如果你知道你在这个帐户中使用的每个终端和每个工具都是UTF-8,那么在你的profile
或类似设置中设置它可能是值得的,尽管如果不是这样的话,这是一个可怕的想法sys.stdout.encoding
并使用'UTF-8'
编码将其换行None
。.encode('UTF-8')
您打印的所有内容。