我正在编写一个Python(Python 3.3)程序,使用POST方法将一些数据发送到网页。主要用于调试过程我得到页面结果并使用print()
函数在屏幕上显示它。
代码是这样的:
conn.request("POST", resource, params, headers)
response = conn.getresponse()
print(response.status, response.reason)
data = response.read()
print(data.decode('utf-8'));
HTTPResponse
.read()
方法返回编码页面的bytes
元素(这是一个结构良好的UTF-8文档)直到我停止使用IDLE GUI for Windows并使用它似乎没问题而是Windows控制台。返回的页面有一个U + 2014字符(em-dash),打印功能可以在Windows GUI中很好地转换(我假定代码页1252),但不在Windows控制台中(代码页850)。鉴于strict
默认行为,我收到以下错误:
UnicodeEncodeError: 'charmap' codec can't encode character '\u2014' in position 10248: character maps to <undefined>
我可以使用这个非常难看的代码修复它:
print(data.decode('utf-8').encode('cp850','replace').decode('cp850'))
现在用?
替换有问题的字符“ - ”。不是理想的情况(连字符应该是更好的替代品),但足以达到我的目的。
我的解决方案中有几件我不喜欢的东西。
问题不在于emdash(我可以想到解决这个问题的几种方法),但我需要编写健壮的代码。我正在向页面提供来自数据库的数据,并且数据可以返回。我可以预见到许多其他相互矛盾的情况:'Á'U+ 00c1(在我的数据库中可能)可以转换为CP-850(西欧语言的DOS / Windows控制台编码)但不能转换为CP-437(美国的编码)英语,在许多Windows instalations中都是默认的。)
所以,问题是:
是否有更好的解决方案使我的代码与输出接口编码无关?
答案 0 :(得分:99)
我看到三个解决方案:
更改输出编码,因此始终输出UTF-8。参见例如Setting the correct encoding when piping stdout in Python,但我无法让这些例子起作用。
以下示例代码使输出可以识别您的目标字符集。
# -*- coding: utf-8 -*-
import sys
print sys.stdout.encoding
print u"Stöcker".encode(sys.stdout.encoding, errors='replace')
print u"Стоескер".encode(sys.stdout.encoding, errors='replace')
此示例使用问号正确替换了我名字中的任何不可打印字符。
如果您创建自定义打印功能,例如名为myprint
,使用这些机制正确编码输出,你可以简单地用myprint
替换打印,而不会使整个代码看起来很丑。
在软件开头全局重置输出编码:
页面http://www.macfreek.nl/memory/Encoding_of_Python_stdout有一个很好的摘要如何更改输出编码。特别是“Stdout周围的StreamWriter Wrapper”部分很有意思。基本上它说要改变I / O编码功能,如下所示:
在Python 2中:
if sys.stdout.encoding != 'cp850':
sys.stdout = codecs.getwriter('cp850')(sys.stdout, 'strict')
if sys.stderr.encoding != 'cp850':
sys.stderr = codecs.getwriter('cp850')(sys.stderr, 'strict')
在Python 3中:
if sys.stdout.encoding != 'cp850':
sys.stdout = codecs.getwriter('cp850')(sys.stdout.buffer, 'strict')
if sys.stderr.encoding != 'cp850':
sys.stderr = codecs.getwriter('cp850')(sys.stderr.buffer, 'strict')
如果在CGI输出HTML中使用,您可以将'strict'替换为'xmlcharrefreplace',以获取不可打印字符的HTML编码标记。
随意修改方法,设置不同的编码,....注意它仍然不能输出非指定的数据。因此,任何数据,输入,文本都必须正确转换为unicode:
# -*- coding: utf-8 -*-
import sys
import codecs
sys.stdout = codecs.getwriter("iso-8859-1")(sys.stdout, 'xmlcharrefreplace')
print u"Stöcker" # works
print "Stöcker".decode("utf-8") # works
print "Stöcker" # fails
答案 1 :(得分:28)
根据DirkStöcker的回答,这里是Python 3的打印功能的整洁包装函数。使用它就像使用print一样。
作为一个额外的好处,与其他答案相比,这不会将您的文本打印为bytearray('b“内容”'),而是作为普通字符串('content'),因为最后一个解码步骤。
def uprint(*objects, sep=' ', end='\n', file=sys.stdout):
enc = file.encoding
if enc == 'UTF-8':
print(*objects, sep=sep, end=end, file=file)
else:
f = lambda obj: str(obj).encode(enc, errors='backslashreplace').decode(enc)
print(*map(f, objects), sep=sep, end=end, file=file)
uprint('foo')
uprint(u'Antonín Dvořák')
uprint('foo', 'bar', u'Antonín Dvořák')
答案 2 :(得分:25)
出于调试目的,您可以使用print(repr(data))
。
要显示文本,请始终打印Unicode。不要在您的脚本中对您的环境的字符编码进行硬编码,例如cp850
。要解码http响应,请参阅A good way to get the charset/encoding of an HTTP response in Python。
要将Unicode打印到Windows控制台,您可以use win-unicode-console
package。
答案 3 :(得分:17)
我深入研究了这一点,并找到了最佳解决方案。
http://blog.notdot.net/2010/07/Getting-unicode-right-in-Python
在我的情况下,我解决了“UnicodeEncodeError:'charmap'编解码器无法编码字符”
原始代码:
print("Process lines, file_name command_line %s\n"% command_line))
新代码:
print("Process lines, file_name command_line %s\n"% command_line.encode('utf-8'))
答案 4 :(得分:15)
如果您使用Windows命令行打印数据,则应使用
chcp 65001
这对我有用!
答案 5 :(得分:1)
如果您使用Python 3.6(可能是3.5或更高版本),它不会再向我提供该错误。我遇到了类似的问题,因为我使用的是v3.4,但是在我卸载并重新安装后它就消失了。