2

我有以下简单的程序:

# -*- coding: utf-8 -*-

GREEK = u'ΑΒΓΔ ΕΖΗΘ ΙΚΛΜ ΝΞΟΠ ΡΣΤΥ ΦΧΨΩ αβγδ εζηθ ικλμ νξοπ ρςτυ φχψω'

print GREEK

正如预期的那样,在终端上运行它会产生:

$ python test.py
ΑΒΓΔ ΕΖΗΘ ΙΚΛΜ ΝΞΟΠ ΡΣΤΥ ΦΧΨΩ αβγδ εζηθ ικλμ νξοπ ρςτυ φχψω

但是将输出传递到另一个程序会导致错误:

$ python test.py | less

Traceback (most recent call last):
  File "test.py", line 5, in <module>
    print GREEK
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: ordinal not in range(128)
Traceback (most recent call last):
  File "ddd.py", line 5, in <module>
    print GREEK
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: ordinal not in range(128)
  • 为什么会失败?为什么重定向会影响程序的运行方式?我本来希望在 shell 中运行的程序总是被重定向:有时到终端程序,有时到另一个程序(less在这种情况下)。为什么“目标”程序会影响源程序的执行?
  • 我可以做些什么来确保程序运行独立于它是发送到终端还是发送到另一个目的地?
4

2 回答 2

7

基于this an other related questions,我实现了以下解决方案,它似乎非常健壮,不需要对我的代码库的所有打印语句进行任何更改:

# -*- coding: utf-8 -*-

import sys

def set_output_encoding(encoding='utf-8'):
    import sys
    import codecs
    '''When piping to the terminal, python knows the encoding needed, and
       sets it automatically. But when piping to another program (for example,
       | less), python can not check the output encoding. In that case, it 
       is None. What I am doing here is to catch this situation for both 
       stdout and stderr and force the encoding'''
    current = sys.stdout.encoding
    if current is None :
        sys.stdout = codecs.getwriter(encoding)(sys.stdout)
    current = sys.stderr.encoding
    if current is None :
        sys.stderr = codecs.getwriter(encoding)(sys.stderr)

GREEK = u'ΑΒΓΔ ΕΖΗΘ ΙΚΛΜ ΝΞΟΠ ΡΣΤΥ ΦΧΨΩ αβγδ εζηθ ικλμ νξοπ ρςτυ φχψω'

set_output_encoding()

print GREEK
print >> sys.stderr, GREEK

要对此进行测试:

python ddd.py             # Do not pipe anything
python ddd.py | less      # Pipe stdout, let stderr go to the terminal
python ddd.py 2>&1 | less # Pipe both stdout and stderr to less

它们都产生了预期的:

ΑΒΓΔ ΕΖΗΘ ΙΚΛΜ ΝΞΟΠ ΡΣΤΥ ΦΧΨΩ αβγδ εζηθ ικλμ νξοπ ρςτυ φχψω
ΑΒΓΔ ΕΖΗΘ ΙΚΛΜ ΝΞΟΠ ΡΣΤΥ ΦΧΨΩ αβγδ εζηθ ικλμ νξοπ ρςτυ φχψω
于 2013-10-31T07:49:01.537 回答
0

您的输出程序的编码不支持这些字符。另一种方法是始终对程序之外的任何内容进行编码,并在需要时将其解码回来。

# -*- coding: utf-8 -*-

GREEK = u'ΑΒΓΔ ΕΖΗΘ ΙΚΛΜ ΝΞΟΠ ΡΣΤΥ ΦΧΨΩ αβγδ εζηθ ικλμ νξοπ ρςτυ φχψω'

print GREEK.encode('utf-8')

这可行,但是它只会显示编码字符串,而不是原始字符串,因为您的终端应用程序不使用相同的编码。

于 2013-10-31T01:10:30.750 回答