【问题标题】:UnicodeEncodeError in Python on Windows ConsoleWindows 控制台上 Python 中的 UnicodeEncodeError
【发布时间】:2014-01-02 13:27:05
【问题描述】:

递归目录中的文件并在控制台中打印文件名时出现以下错误:

Traceback (most recent call last):
  File "C:\Program Files\Python33\lib\encodings\cp437.py", line 19, in encode
    return codecs.charmap_encode(input,self.errors,encoding_map)[0]
UnicodeEncodeError: 'charmap' codec can't encode character '\u2013' in position
53: character maps to <undefined>

根据错误,文件名字符串中的一个字符是\u2013,这是一个与常见的-减号不同的EN DASH 字符。

我检查了设置为437 的Windows 编码。现在,我看到我有两个选项可以通过更改 Windows 控制台的编码或从文件名转换 get 中的字符以适应控制台编码来解决此问题。我将如何在 Python 3.3 中做到这一点?

【问题讨论】:

    标签: python python-3.x unicode


    【解决方案1】:

    Windows 控制台正在使用 cp437 编码,并且该编码不支持字符 \u2013。尝试将此添加到您的代码中:

    sys.stdout = io.TextIOWrapper(sys.stdout.buffer,'cp437','backslashreplace')
    

    【讨论】:

    【解决方案2】:

    或将文件名中的字符转换为适合控制台编码

    可能控制台编码已经正确(虽然无法从错误消息中看出)。代码页 437 根本不包含该字符,因此您将无法打印它。

    您可以使用具有后备编码的文本编码器重新打开 stdout,如 iamsudip 使用 backslashreplace 的回答中所示,至少获得可读(如果不能可靠地恢复)输出而不是错误。

    更改 Windows 控制台的编码

    您可以通过在运行 Python 之前执行控制台命令 chcp 1252 来执行此操作,但这仍然只会为您提供不同的有限可打印字符 - 包括 U+2013,但不会有很多其他 Unicode 字符。

    理论上,您可以通过chcp 到 65001 来获得 UTF-8,这将允许您打印任何字符。不幸的是,在 C 运行时的标准 IO 实现中存在严重的错误,这通常使得它在实践中无法使用。

    这种令人遗憾的状况会影响所有使用 MS C 运行时的 stdio 库调用的应用程序,包括 Python 和大多数其他语言,导致 Windows 控制台上的 Unicode 在大多数情况下无法正常工作。

    如果您确实必须将 Unicode 输出到 Windows 控制台,您可以直接使用 ctypes 使用 Win32 WriteConsoleW API,但这并不好玩。

    【讨论】:

    • Python 3.3 应该适用于代码页 65001,请参阅 docs.python.org/dev/whatsnew/3.3.html#codecs
    • @MarkRansom:这不是我的经验。似乎问题在于控制台句柄 Windows 内部将 WriteFile 路由到 WriteConsoleA,它返回解码的 Unicode 字符数而不是写入的字节数。 WriteFile 高兴地将这个错误的数字返回给 CRT 的 write 函数。
    • +1 @eryksun 的描述符合我对这个错误的体验。我也从读取操作中发现了相同的行为,这通常会导致进程停止,等待永远不会出现的进一步输入。我不确定是 CRT 还是 WriteFile 应该受到责备,但无论是哪一个,都存在解决 ANSI 默认多字节代码页(如 932 和 936)的行为的解决方法,但不适用于 65001。MS 非常遗憾多年以来仍未解决此已知问题。
    • ANSICON 修复了我描述的问题。它挂钩 WriteConsoleA 以注入对 ANSI 转义序列的支持。你可以通过设置环境变量ANSICON_API=[!]program;...来告诉它返回字节数而不是字符数。
    • 它将WriteConsoleA 替换为MyWriteConsoleA,它将“[f]调整(大概)正确的计数”。它还将WriteFile 替换为MyWriteFile,后者重定向到MyWriteConsoleA 以获得控制台句柄。
    猜你喜欢
    • 2015-11-18
    • 2016-12-13
    • 1970-01-01
    • 1970-01-01
    • 2017-04-22
    • 1970-01-01
    • 2012-10-21
    • 2012-06-02
    相关资源
    最近更新 更多