10

如果在控制台中运行此代码 - 它运行良好(它是俄语),但如果在 Apache2 服务器上像 cgi 一样运行它 - 它会失败:<type 'exceptions.UnicodeEncodeError'>: 'ascii' codec can't encode characters in position 8-9: ordinal not in range(128). 代码是:

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

import cgitb
cgitb.enable()

print "Content-Type: text/html;charset=utf-8"
print 
s=u'Nikolja \u043d\u0435 \u0421\u0430\u0440\u043a\u043e\u0437\u0438!'
print s#.encode('utf-8')

是的,解决方案是取消注释.encode('utf-8'),但我花了更多时间来理解为什么而不是发生,我看不到答案。

4

2 回答 2

11

从控制台运行时,Python 可以检测控制台的编码,并将打印到控制台的 Unicode 隐式转换为该编码。如果该编码不支持您尝试打印的字符,它仍然会失败。UTF-8 可以支持所有 Unicode 字符,但其他常见的控制台编码(如美国 Windows 上的 cp437)不支持。

当 stdout 不是控制台时,Python 2.X 在无法确定控制台编码时默认为 ASCII。这就是为什么在网络服务器中你必须明确并自己编码你的输出。

例如,从控制台和您的网络服务器尝试以下脚本:

import sys
print sys.stdout.encoding

从控制台你应该得到一些编码,但你应该从 web 服务器得到None. 请注意,Python 2.X 使用ascii但 Python 3.Xutf-8在无法确定编码时使用。

重定向输出时,控制台也可能出现此问题。这个脚本:

import sys
print >>sys.stderr,sys.stdout.encoding
print >>sys.stderr,sys.stderr.encoding

直接运行与重定向时返回以下内容stdout

C:\>test
cp437
cp437

C:\>test >out.txt
None
cp437

Notestderr没有受到影响,因为它没有被重定向。

环境变量PYTHONIOENCODING也可用于覆盖默认的 stdout/stdin 编码。

于 2012-08-01T21:09:40.300 回答
5

尝试在标准输入和标准输出上应用 utf-8 编解码器...

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

import cgitb
import sys
import codecs

sys.stdout = codecs.getwriter('utf-8')(sys.stdout)
# If you need input too, read from char_stream as you would sys.stdin
char_stream = codecs.getreader('utf-8')(sys.stdin)

cgitb.enable()

print "Content-Type: text/html;charset=utf-8"
print 
s=u'Nikolja \u043d\u0435 \u0421\u0430\u0440\u043a\u043e\u0437\u0438!'
print s
于 2012-08-01T17:48:25.410 回答