在Python3中使用printc的编解码器错误处理程序?

时间:2015-04-09 13:24:01

标签: python python-3.x encoding

众所周知,encode()有一个用于编解码器错误处理的error参数,例如:

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

# "发" and "财" are not available in 'big5' encoding
text = "发财了".encode('big5', errors='replace')

但是,errors没有print()个参数,如果我们只是写:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
print("发财了")

如果在带有big5编码的命令提示符下运行,则会引发UnicodeEncodeError异常(例如,在繁体中文版Windows中)。

有没有办法让print()行为像encode(),它接受​​更多处理程序,例如replacebackslashreplacexmlcharrefreplace,以便字符串可以安全打印而不会引发异常吗?

2 个答案:

答案 0 :(得分:2)

这是我目前的解决方案:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys

def safeprint(*args, errors='backslashreplace', **kargs):
    """
    Print safely and skips error decode.

    Acts like print() with an additional "errors" argument to determine the
    error handler for codec errors and accepts non-str-or-None types for the
    "sep" and "end" arguments.
    """
    e = (kargs['file'] if 'file' in kargs else sys.stdout).encoding
    args = [str(x) for x in args]
    sep = str(kargs['sep']) if 'sep' in kargs and kargs['sep'] is not None else " "
    end = str(kargs['end']) if 'end' in kargs and kargs['end'] is not None else "\n"
    text = sep.join(args) + end
    kargs['sep'] = ""
    kargs['end'] = ""
    print(text.encode(e, errors).decode(e, errors), **kargs)

if __name__ == "__main__":
    safeprint("Hello World!", "你好世界!", "ハローワールド", "हैलो वर्ल्ड")
    safeprint("Hello World!", "你好世界!", "ハローワールド", "हैलो वर्ल्ड", errors="ignore")
    safeprint("Hello World!", "你好世界!", "ハローワールド", "हैलो वर्ल्ड", errors="replace")
    safeprint("Hello World!", "你好世界!", "ハローワールド", "हैलो वर्ल्ड", errors="backslashreplace")
    safeprint("Hello World!", "你好世界!", "ハローワールド", "हैलो वर्ल्ड", errors="xmlcharrefreplace")
    safeprint("Hello World!", "你好世界!", "ハローワールド", "हैलो वर्ल्ड", sep=None, end=str)
    safeprint("Hello World!", "你好世界!", "ハローワールド", "हैलो वर्ल्ड", sep=" -发- ", end=" -财- \n")
    with open("safeprint_big5.log", "w", encoding="big5") as f:
        safeprint("Hello World!", "你好世界!", "ハローワールド", "हैलो वर्ल्ड", file=f)
    with open("safeprint_gbk.log", "w", encoding="gbk") as f:
        safeprint("Hello World!", "你好世界!", "ハローワールド", "हैलो वर्ल्ड", file=f)
    with open("safeprint_utf8.log", "w", encoding="utf-8") as f:
        safeprint("Hello World!", "你好世界!", "ハローワールド", "हैलो वर्ल्ड", file=f)

这种方法使自定义函数safeprint()与原生print()一样具有以下差异:

  1. 还有一个errors参数来确定如何处理编解码器错误(backslashreplace为默认值)。

  2. sepend参数接受str或None以外的类型。

  3. safeprint()检查本地print()应该写入的输出文件的编码,然后对所有文本参数进行编码,因此所有可打印的字符都按原样打印,并打印所有不可打印的字符如转型。

    尽管之前对所有正在打印的文本进行编码和解码似乎效率低下,但原生encode()decode()基于C并且运行速度非常快。在测试中,我在utf8控制台中打印一些带有utf8兼容纯文本的文章5000次,原生print()需要0:00:02.366799safeprint()需要0:00:02.915871。它证明了性能下降几乎可以忽略不计。

    上述脚本可以保存为模块脚本,比如safeprint.py。其他脚本可以使用from safeprint import safeprint并使用safeprint(),甚至可以使用from safeprint import safeprint as print覆盖原生print(),以便print()可以像safeprint()一样工作确实。

答案 1 :(得分:0)

使用try .. except block包装你的print函数,并捕获UnicodeEncodeError异常:

try:
   print("发财了")
except UnicodeEncodeError:
   handle_encode_error()

您可以决定如何在异常块中转换字符串。