在Emacs中使用Python进行Unicode转换的问题


问题内容

我试图了解在命令行运行与作为Emacs elisp函数的一部分运行时Python脚本行为的区别。

脚本看起来像这样(我使用的是Python 2.7.1 BTW):

import json; t = {"Foo":"ザ"}; print json.dumps(t).decode("unicode_escape")

也就是说,[通常]选取包含Unicode字符的JSON段,将其转储为Unicode逸出版本,然后将其解码回Unicode表示形式。在命令行上运行时,其转储部分返回:

'{"Foo": "\\u30b6"}'

打印时如下所示:

'{"Foo": "\u30b6"}'

解码部分如下所示:

u'{"Foo": "\u30b6"}'

打印时如下所示:

{"Foo": "ザ"}

即,至少在支持unicode的终端/控制台中(在我的测试平台中为xterm),该结构的原始字符串表示形式。在Windows控制台中,关于unicode字符的输出不正确,但是脚本不会出错。

在Emacs中,转储转换与命令行上的转换相同(至少与打印确认一样),但解码部分会因恐惧而崩溃:

UnicodeEncodeError中的文件“”,第1行:’ascii’编解码器无法在位置9编码字符u’\ u30b6’:序数不在range(128)中

我觉得我在这里缺少有关脚本或Emacs的一些基本知识(在我的测试平台23.1.1中)。打印过程中是否存在一些自动魔术部分,调用了在命令行中发生但在Emacs中没有发生的正确编解码器/语言环境?我试过显式设置Emacs调用的语言环境(这是一个没有json逻辑的存根测试):

"LC_ALL=\"en_US.UTF-8\" python -c 's = u\"Fooザ\"; print s'"

产生相同的异常,而

"LC_ALL=\"en_US.UTF-8\" python -c 'import sys; enc=sys.stdout.encoding; print enc' "

表示编码为“无”。

如果我尝试使用以下方法强制转换:

"LC_ALL=\"en_US.UTF-8\" python -c 's = u\"Fooザ\"; print s.encode(\"utf8\",\"replace\")'"

错误消失了,但是结果是在非Unicode控制台中看到的字符串的“乱码”版本:

Fooa?¶

有任何想法吗?

更新:感谢unutbu -b /
c语言环境标识下降,该命令需要用utf8-encode显式修饰(请参见直接使用unicode字符串的答案)。就我而言,我从dumps/decode序列中得到了所需的东西,因此我添加了额外的必需装饰以实现所需的结果:

import json; t = {"Foo":"ザ"}; print json.dumps(t).decode("unicode_escape").encode("utf8","replace")

请注意,这是“原始” Python,没有Emacs所需的必要转义。

正如你可能已经从看这个问题,原有的部分猜测,我用这个作为在Emacs一些JSON格式逻辑的一部分-见我的回答这个问题


问题答案:

Python的wiki页面, “PrintFails”

当Python未检测到所需的输出字符集时,它将sys.stdout.encoding设置为None,然后print将调用“ ascii”编解码器。

看起来,当从elisp函数运行python时,它无法检测到所需的字符集,因此默认情况下为“
ascii”。因此,尝试打印unicode会默认导致python将unicode编码为ascii,这就是错误的原因。


更换u\"Fooザ\"u\"Foo\\u30b6\"似乎工作:

(defun mytest ()
  (interactive)
  (shell-command-on-region (point)
         (point) "LC_ALL=\"en_US.UTF-8\" python -c 's = u\"Foo\\u30b6\"; print s.encode(\"utf8\",\"replace\")'" nil t))

C-x C-e M-x mytest

产量

Fooザ