python - UnicodeEncodeError : 'charmap' codec can'

我正在编写一个 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 文档)它在我停止使用 Windows 的 IDLE GUI 并改用 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'))

现在它用 ? 替换有问题的字符“-”。不是理想的情况(连字符应该是更好的替代品),但足以满足我的目的。

我的解决方案中有几处我不喜欢。

  1. 所有解码、编码和解码的代码都很难看。
  2. 它解决了这种情况的问题。如果我为使用其他编码(latin-1、cp437、回到 cp1252 等)的系统移植程序,它应该能够识别目标编码。它不是。 (例如,当再次使用 IDLE GUI 时,emdash 也会丢失,这在以前没有发生过)
  3. 如果将 emdash 翻译成连字符而不是询问音会更好。

问题不在于 emdash(我可以想出几种方法来解决这个特别的问题),但我需要编写健壮的代码。我正在向页面提供来自数据库的数据,并且该数据可以返回。我可以预料到许多其他冲突的情况:'Á' U+00c1(可能在我的数据库中)可以转换为 CP-850(用于西欧语言的 DOS/Windows 控制台编码)但不能转换为 CP-437(用于美国的编码)英语,这是许多 Windows 安装中的默认设置)。

那么问题来了:

是否有更好的解决方案使我的代码与输出接口(interface)编码无关?

最佳答案

我看到了三个解决方案:

  1. 更改输出编码,使其始终输出 UTF-8。参见例如Setting the correct encoding when piping stdout in Python ,但我无法让这些示例正常工作。

  2. 以下示例代码使输出了解您的目标字符集。

    # -*- 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,使用该机制对输出进行正确编码,您可以在必要时将 print 替换为 myprint,而不会使整个代码看起来很丑。

  3. 在软件开始时全局重置输出编码:

    页面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
    

关于python - UnicodeEncodeError : 'charmap' codec can't encode - character maps to <undefined>, 打印函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14630288/

相关文章:

python - 如何从 Python 中的字典中提取所有值?

python - 如何从 Python 中的 URL 读取图像数据?

python - 规范化数据框的列

python - 在 Linux 上通过 Python 脚本截取屏幕截图

linux - 将 cron 选项卡设置为工作日的特定时间

linux - 如何为长路径制作 "alias"?

python - 如何更改 seaborn 轴或图形级别图的图形大小

python - 什么时候应该使用 Flask.g?

c - 如何在C程序中列出目录中的文件?

linux - 提取并删除目录中的所有.gz - Linux