Python2.7打印Unicode字符串仍然出现UnicodeEncodeError:'ascii'编解码器无法编码字符...序数不在范围内(128)

4
一个简单的打印函数
def TODO(message):
    print(type(message))
    print(u'\n~*~ TODO ~*~ \n %s\n     ~*~\n' % message)

被称为这样
TODO(u'api servisleri için input check decorator gerekiyor')

导致此错误的原因是

<type 'unicode'>                                                                                 
Traceback (most recent call last):                                                               
  File "/srv/www/proj/__init__.py", line 38, in <module>                                      
    TODO(u'api servisleri için input check decorator gerekiyor')                                 
  File "/srv/www/proj/helpers/utils.py", line 33, in TODO                                     
    print(u'\n~*~ TODO ~*~ \n %s\n     ~*~\n' % message)                                         
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe7' in position 32: ordinal not in range(128)

但它在ipython控制台中运行正常。
In [10]: TODO(u'api servisleri için input check decorator gerekiyor')
<type 'unicode'>

~*~ TODO ~*~ 
 api servisleri için input check decorator gerekiyor
     ~*~

这段代码在Python 2.7.12上可以运行,但在2.7.9上出现了错误。

我在这里做错了什么?

编辑:当在Flask应用程序中调用此函数时会失败,在Python控制台中可以正常工作。


1
我假设你正在使用Un*x系统。请参考:http://stackoverflow.com/a/35839964/1554386 - Alastair McCormack
没有更多信息,我投票将其关闭为“无法重现”。这很可能是一个简单的本地化问题。 - Alastair McCormack
@AlastairMcCormack 本地用的是Mint 18,远程用的是Debian Jessie。locale命令在两个系统上输出相同的结果。远程机器上出现了故障,但似乎本地机器也存在问题,因为它本应该失败但却没有。请查看我的回答以获得详细信息。 - altunyurt
在您的失败系统上,同时在iPython和Python中运行以下命令:import locale; locale.getpreferredencoding() - Alastair McCormack
1
@AlastairMcCormack 两者都是“UTF-8”。 - altunyurt
显示剩余7条评论
3个回答

0
不同的终端(和GUI)允许使用不同的编码方式。我手头没有最新的ipython,但它显然能够处理字符串中的非ASCII字符0xe7'ç')。然而,您的普通控制台正在使用'ascii'编码(在异常中以名称提到),该编码无法显示大于0x7f的任何字节。
如果您想将非ASCII字符串打印到ASCII控制台,则必须决定如何处理它无法显示的字符。 str.encode方法提供了几个选项:

str.encode([encoding[, errors]])

errors 可以被指定为一个不同的错误处理方案。 errors 的默认设置是 'strict',意味着编码错误会引发一个 UnicodeError。 其他可能的值包括 'ignore''replace''xmlcharrefreplace''backslashreplace' 和通过 codecs.register_error() 注册的任何其他名称,请参见 编解码器基类 章节。

以下是一个示例,它在字符串上使用了这四种替代的错误处理程序(没有添加由 TODO 添加的额外修饰):

#!/usr/bin/env python2
# -*- coding: utf-8 -*-

from __future__ import print_function

uni = u'api servisleri için input check decorator gerekiyor'
handlers = ['ignore', 'replace', 'xmlcharrefreplace', 'backslashreplace']
for handler in handlers:
    print(handler + ':')
    print(uni.encode('ascii', handler))
    print()

输出:

ignore:
api servisleri iin input check decorator gerekiyor

replace:
api servisleri i?in input check decorator gerekiyor

xmlcharrefreplace:
api servisleri i&#231;in input check decorator gerekiyor

backslashreplace:
api servisleri i\xe7in input check decorator gerekiyor

哪一个输出结果最接近你想要的,这就由你决定。

更多信息请参见Python 2的“Unicode HOWTO”以及Ned Batchelder的“Pragmatic Unicode, or, How Do I Stop the Pain?”,还可以观看2012 PyCon美国36分钟的视频

编辑:或者,正如你已经发现的那样,你的终端可以很好地显示Unicode,但是你的默认编码仍然设置为'ascii',这比它需要的限制更多。


-1
“ç” 是 UTF-8 字符集中代表小写字母“c”的字符之一。Python 2.7.9 可能使用 ASCII 编码。您可以在任何版本的 Python 中运行下面的代码,以模拟 Python 2.7.9 的行为。
import sys; 
# -*- coding: utf-8 -*-

def TODO(message):
    print(type(message))
    print(u'\n~*~ TODO ~*~ \n %s\n     ~*~\n' % message)

message = u'api servisleri için input check decorator gerekiyor'
encodedMessage = message.encode('ascii')

print(sys.stdout.encoding)
TODO(encodedMessage)

它将抛出异常

追踪(最近一次调用):文件“test.py”,第9行,

encodedMessage = message.encode('ascii') UnicodeEncodeError: 'ascii' codec can't encode character '\xe7' in position 16: ordinal not in range(128)

因此,问题与解释器的编码规则有关。您可以自己进行编码或忽略。

希望这将是有用的


-1

显然,print函数与print语句有些不同。

https://docs.python.org/2.7/library/functions.html#print

All non-keyword arguments are converted to strings like 
str() does and written to the stream, separated by sep 
and followed by end. 

简单地说,对Unicode字符串进行编码就解决了这个问题。
msg = u'\n~*~ TODO ~*~ \n %s\n     ~*~\n' % message
print(msg.encode("utf-8"))

不过,还不确定为什么它在2.7.12版本上可以运行,也许是地区设置的问题?


1
这不是答案。请参考@Alastair的评论并修复您的环境。您所做的是手动编码为UTF-8,这在非UTF8终端上无法正常工作。将您的终端配置正确地报告给Python UTF-8,然后 print u'için' 就可以正常工作了。print函数与语句的区别是一个转移话题,Python 2中没有打印函数,除非您使用 from __future__ import print_function。它在Python 3中变成了一个函数。 - Mark Tolonen
两个环境具有相同的本地化输出。正如我所提到的文件中所述,这是打印函数的预期输出。这是在打印功能失败的机器上打印的输出。 `╰─$ python Python 2.7.9(默认值,Jun 29 2016,13:08:31) [GCC 4.9.2] on linux2 键入“help”、“copyright”、“credits”或“license”以获取更多信息。
print u'için' için`
- altunyurt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接