PHP系统、Python与UTF-8

3 投票
2 回答
2492 浏览
提问于 2025-04-17 01:53

我有一个运行得很好的Python程序。这个程序可以连接到几个网站,并输出我想要的信息。因为并不是所有网站都使用utf-8编码,所以我从响应头中请求字符集,并使用unicode(string, encoding)方法来解码(我不太确定这样做是否合适,但效果还不错)。当我直接运行这个Python程序时,没有出现???这样的标记,一切正常。但是当我通过PHP的system函数来运行这个程序时,就出现了错误:

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

这个错误是Python特有的,但让我困惑的是,当我在终端运行程序时并不会出现这个错误。只有在通过PHP的system函数调用程序时,才会出现这个问题。这可能是什么原因呢?

以下是一个示例代码:

调用Python程序的PHP代码:

system("python somefile.py $search") // where $search is the variable coming from an input

Python代码:

encoding = "iso-8859-9"
l = "some string here with latin characters"
print unicode("<div class='line'>%s</div>" % l, encoding)
# when I run this code from terminal it works perfect and I receive no ??? marks
# when I run this code from php, I receive the error above

2 个回答

2

当你在终端运行Python脚本时,你的终端很可能是用UTF8编码的(特别是如果你在使用Linux或Mac的话)。

当你把变量l设置为"一些包含拉丁字符的字符串"时,这个字符串会按照默认编码进行编码。如果你在终端中,l的编码就是UTF8,这样脚本就不会崩溃。

小贴士:如果你有一个用latin1编码的字符串,想把它转换成unicode格式,你可以这样做:

variable.decode('latin1')

4

来自PrintFails wiki的内容:

当Python发现它的输出连接到一个终端时,它会把sys.stdout.encoding这个属性设置为终端的编码方式。这样,打印语句就会自动把Unicode类型的内容转换成字符串输出。

这就是为什么你的程序在终端中运行时能够正常工作的原因。

当Python没有检测到合适的字符集时,它会把sys.stdout.encoding设置为None,这时打印就会使用“ascii”编码。

这就是为什么你的程序在通过PHP调用时会失败的原因。为了让它在PHP中正常工作,你需要明确告诉print应该使用什么编码。例如,如果你想在没有连接到终端的情况下输出为utf-8编码,可以这样做:

ENCODING = sys.stdout.encoding if sys.stdout.encoding else 'utf-8'
print unicode("<div class='line'>%s</div>" % l, encoding).encode(ENCODING)

另外,你也可以设置PYTHONIOENCODING环境变量。这样你的代码就可以在终端和通过PHP调用时都正常工作,而不需要做其他修改。

撰写回答