UnicodeEncodeError:“charmap”编解码器无法编码 - 字符映射到<未定义>,打印函数[重复]

2023-12-23

我正在编写一个 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'));

the 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. 如果将破折号翻译为连字符而不是审讯爆炸,那就更好了。

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

那么,问题是:

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


我看到了三种解决方案:

  1. 更改输出编码,因此它将始终输出 UTF-8。参见例如在 Python 中管道 stdout 时设置正确的编码 https://stackoverflow.com/questions/492483/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 http://www.macfreek.nl/memory/Encoding_of_Python_stdout有一个很好的总结如何更改输出编码。尤其是“StreamWriter Wrapper around Stdout”部分很有趣。本质上它说的是改变 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
    
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

UnicodeEncodeError:“charmap”编解码器无法编码 - 字符映射到<未定义>,打印函数[重复] 的相关文章

随机推荐