无论环境如何,都在python中打印unicode字符串

时间:2014-12-07 21:00:38

标签: python unicode encoding utf-8

我正在尝试找到一个从python脚本中打印unicode字符串的通用解决方案。

要求是它必须在任何平台上的python 2.7和3.x以及任何终端设置和环境变量(例如LANG = C或LANG = en_US.UTF-8)中运行。

python打印功能在打印时自动尝试编码为终端编码,但如果终端编码为ascii则失败。

例如,当环境“LANG = enUS.UTF-8”时,以下内容有效:

x = u'\xea'
print(x)

但是当“LANG = C”时,它在python 2.7中失败了:

UnicodeEncodeError: 'ascii' codec can't encode character u'\xea' in position 0: ordinal not in range(128)

以下方法无论LANG设置如何,但如果终端使用不同的unicode编码,则无法正确显示unicode字符:

print(x.encode('utf-8'))

如果可能的话,所需的行为是始终在终端中显示unicode,如果终端不支持unicode,则显示一些编码。例如,如果终端仅支持ascii,则输出将为UTF-8编码。基本上,目标是在python打印函数工作时做同样的事情,但是在打印函数失败的情况下,使用一些默认编码。

4 个答案:

答案 0 :(得分:9)

您可以通过告知LANG=C默认为UTF-8来处理sys.stdout案例,否则将默认为ASCII。

import sys, codecs

if sys.stdout.encoding is None or sys.stdout.encoding == 'ANSI_X3.4-1968':
    utf8_writer = codecs.getwriter('UTF-8')
    if sys.version_info.major < 3:
        sys.stdout = utf8_writer(sys.stdout, errors='replace')
    else:
        sys.stdout = utf8_writer(sys.stdout.buffer, errors='replace')

print(u'\N{snowman}')

上面的代码段符合您的要求:它适用于Python 2.7和3.4,当LANG处于非{1}}等非UTF-8设置时,它不会中断。< / p>

这是not a new technique,但在文档中很难找到。如上所述,它实际上遵循非UTF-8设置,例如C。如果Python伪装成ASCII,打破了应用程序,它只默认为UTF-8。

答案 1 :(得分:1)

我认为你不应该尝试在Python级别解决这个问题。记录您的应用程序需求,记录您运行的系统的区域设置,以便将其包含在错误报告中,并将其保留在该区域。

如果你想走这条路,至少要区分终端和管道;你永远不应该将数据输出到终端无法明确处理的终端;例如,不输出UTF-8,因为不可打印的代码点&gt; U + 007F最终可能在编码时被解释为控制代码。

对于管道,默认输出UTF-8并使其可配置。

所以你要检测是否正在使用TTY,然后根据它处理编码;对于终端,设置错误处理程序(选择replacebackslashreplace中的一个,以便为无法处理的任何字符提供替换字符或转义序列。对于管道,请使用可配置的编解码器。

import codecs
import os
import sys

if os.istty(sys.stdout.fileno):
    output_encoding = sys.stdout.encoding
    errors = 'replace'
else:
    output_encoding = 'utf-8'  # allow override from settings
    errors = None  # perhaps parse from settings, not needed for UTF8
sys.stdout = codecs.getwriter(output_encoding)(sys.stdout, errors=errors)

答案 2 :(得分:0)

您可以使用特殊参数'backslashreplace'自行编码字符串,以便将不可表示的字符转换为转义序列。在Python 2中,您可以直接打印encode的结果,但在Python 3中,您需要先decode将其返回到Unicode。

import sys
encoding = sys.stdout.encoding
print(s.encode(encoding, 'backslashreplace').decode(encoding))

如果sys.stdout.encoding没有提供您的终端可以处理的值,那么您必须处理这个问题。

答案 3 :(得分:-1)

您可以处理异常:

def always_print(s):
    try:
        print(s)
    except UnicodeEncodeError:
        print(s.encode('utf-8'))