使用Python将ASCII转换为UTF-8

3

我有一个用Python编写的XMPP机器人。它的插件之一可以执行操作系统命令并将输出发送给用户。据我所知,为了通过XMPP协议发送它,输出应该类似于Unicode。因此,我尝试以以下方式处理它:

output = os.popen(cmd).read() 
if not isinstance(output, unicode):
   output = unicode(output,'utf-8','ignore')
bot.send(xmpp.Message(mess.getFrom(),output))

但是,当输出中出现俄语字符时,它们并不能被很好地转换。

sys.getdefaultencoding() 

表示默认命令提示符编码为'ascii',但是当我尝试执行以下操作时

output.decode('ascii') 

在 Python 控制台中,我收到以下信息:
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0x92 in position 1: 
ordinal not in range(128)

操作系统:Win XP,Python 2.5.4 提示:抱歉我的英语不好 :(


1
你尝试过输出output = output.encode("utf-8")吗? - dbr
转换为output.decode('866')对我有帮助。但是locale.getpreferredencoding(do_setlocale=True)返回cp1251。是否有其他方法确定正确的编码?因为这个机器人也应该在Linux上工作。 - colriot
额... ASCII 已经是 UTF-8 的一个完美子集了!任何 ASCII 文本都是 UTF-8 文本,根据定义。这里是想要反过来转换编码为 UTF-8 吗?还是 colriot 想要将其他编码转换为 UTF-8? - Arafangion
4个回答

3

sys.getdefaultencoding() 返回 Python 的默认编码 - 除非您已更改它,否则为 ASCII。ASCII 不支持俄语字符。

您需要确定实际文本的编码方式,可以手动进行,也可以使用 locale 模块 进行操作。

通常类似于:

import locale
encoding = locale.getpreferredencoding(do_setlocale=True

在Windows上,即使在模拟MS-DOS命令提示符下运行Python,该设置将为OP的(俄语)设置提供cp1251,而OP需要cp866 - John Machin

2
ASCII没有定义127 0x7F以上的字符值。也许你是指西里尔字母代码页?它是866。
请参见http://en.wikipedia.org/wiki/Code_page 编辑:由于此答案被标记为正确,因此886应该可以使用,但正如其他答案所指出的那样,886并不是唯一的俄语代码页。如果您使用与编码俄语符号时使用的代码页不同的代码页,则会得到错误的结果。

请使用真实名称“KOI8-R”,而不是不透明的Windows名称“CP866”。 - Glenn Maynard
但是 a.decode('cp866') 和 a.decode('koi8-r') 的结果是不同的。 - colriot
如果有Cyrillic代码页的可移植标识符,最好使用它。Glenn,你有KOI8-R的参考资料吗? - John Knoeller
代码页866与KOI8-R或其他俄语编码完全不同。作为DOS代码页,您现在很少会遇到它。请参见http://en.wikipedia.org/wiki/Code_page_866与http://en.wikipedia.org/wiki/KOI8-R以及更常见的http://en.wikipedia.org/wiki/Windows-1251。 - bobince

1

你说:“sys.getdefaultencoding() 显示默认命令提示符编码为 'ascii'”

sys.getdefaultencoding 并没有关于“命令提示符”编码的信息。

在 Windows 上,sys.stdout.encoding 应该可以解决问题。在我的机器上,当 Python 在命令提示符窗口中运行时,它包含 cp850,而在 IDLE 中则包含 cp1252。你的应该分别包含 cp866cp1251

更新 你说你仍然需要在 IDLE 中使用 cp866。请注意:

IDLE 2.6.4      
>>> import os
>>> os.popen('chcp').read()
'Active code page: 850\n'
>>>

所以当你的应用程序启动时,检查一下你是否在Windows上运行,如果是,则解析 os.popen('chcp').read() 的结果。冒号前面的文本可能是与区域设置相关的。 codepage = result.split()[-1] 可能足够“解析”了。在没有Windows/MS-DOS分裂人格的Unix上,sys.stdout.encoding 应该是可以的。


还是不行。我如何找出 os.popen(_command_).read()的默认编码?或者它取决于 _command_? - colriot
os.popen("command").read() 默认编码?这个概念不存在。传输数据的编码由写入者选择或强制执行;它与读取者无关,读取者需要知道或猜测编码,或从可靠来源获取编码。你为什么要问这个问题?为什么 sys.stdout.encoding 不完全符合你的要求? - John Machin
因为无论您是从命令提示符还是IDLE运行Python,都没有关系。在这两种情况下,'cp866'都是正确的选择。 - colriot
谢谢。这种方法似乎是理想的。但是当我尝试使用“ipconfig”命令测试机器人时……所以在这种情况下,“cp1251”是输出的真实编码。 这是否意味着没有通用的方法来解决我的问题? - colriot

0
在Python中,'cp855'、'cp866'、'cp1251'、'iso8859_5'和'koi8_r'是不同的俄语代码页。你需要使用正确的代码页来解码popen的输出。在Windows控制台中,'chcp'命令列出了控制台命令使用的代码页。但这不一定是Windows应用程序使用的代码页。在美国的Windows上,控制台使用'cp437',而像记事本这样的应用程序则使用'cp1252'。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接