【问题标题】:Unicode with cp1251 and utf-8 on windowsWindows 上带有 cp1251 和 utf-8 的 Unicode
【发布时间】:2016-03-04 15:29:32
【问题描述】:

我在 python 中玩unicode

所以有一个简单的脚本:

# -*- coding: cp1251 -*-

print 'юникод'.decode('cp1251')
print unicode('юникод', 'cp1251')
print unicode('юникод', 'utf-8')

在 cmd 中,我已将编码切换为 Active code page: 1251

还有输出:

СЋРЅРёРєРѕРґ
СЋРЅРёРєРѕРґ
юникод

我有点困惑。

由于我已将编码指定为cp1251,因此我希望它会被正确解码。

但结果有一些垃圾代码点被解释。 我知道'юникод' 只是一个字节,例如: '\xd1\x8e\xd0\xbd\xd0\xb8\xd0\xba\xd0\xbe\xd0\xb4'.

但是有一种方法可以使用cp1251 在终端中获得正确的输出? 我应该手动构建字节字符串吗?

我好像误会了什么。

【问题讨论】:

  • 你能突出显示你想要它的样子吗?
  • 我希望我的终端中的 print unicode('юникод', 'cp1251')юникод 而不是垃圾符号。

标签: python python-2.7 unicode encoding


【解决方案1】:

我想我能理解发生在你身上的事情。最后一行给了我提示,您的 垃圾代码点 已确认。您尝试显示 cp1251 字符,但您的编辑器配置为使用 utf8。

# -*- coding: cp1251 -*- 仅由 Python 解释器用于转换来自 ASCII 范围之外的源 Python 文件的字符。无论如何,它仅用于 unicode litterals,因为来自原始源的字节给出了呃......字节字符串中完全相同的字节。一些文本编辑器可以自动使用这一行(IDLE 编辑器是),但我对此缺乏信心,并且在我使用 gvim 时总是将 手动 切换到正确的编码。短篇小说:# -*- coding: cp1251 -*- 在您的代码中未使用,只会误导读者,因为它不是实际的编码。

如果您想确定源代码中的内容,最好使用显式转义。在代码页 1251 中,这个词 юникод 由这些字符组成:'\xfe\xed\xe8\xea\xee\xe4'

如果你写这个来源:

txt = '\xfe\xed\xe8\xea\xee\xe4'
print txt
print txt.decode('cp1251')
print unicode(txt, 'cp1251')
print unicode(txt, 'utf-8')

并在配置为使用 CP1251 字符集的控制台中执行它,前三行将输出 юникод,最后一行将抛出 UnicodeDecodeError 异常,因为输入不再是有效的 'utf8'。

或者,如果您对当前的编辑感到满意,您可以这样写:

# -*- coding: utf8 -*-

txt = 'юникод'.decode('utf8').encode('cp1251') # or simply txt = u'юникод'.encode('cp1251')
print txt
print txt.decode('cp1251')
print unicode(txt, 'cp1251')
print unicode(txt, 'utf-8')

应该给出相同的结果 - 但现在声明的源编码应该是你的 python 源的实际编码。


顺便说一句,原生使用 unicode 的 Python 3.5 IDLE 证实:

>>> 'СЋРЅРёРєРѕРґ'.encode('cp1251').decode('utf8')
'юникод'

【讨论】:

  • 我无法完全执行此代码,因为我的系统使用 CP1252,所以我使用 'éè' 而不是 'юникод' 和 1252 而不是 1251...
  • 好收获!你完全正确。那个unicode真的很痛苦:D
  • @xi_:这个问题比这个答案所暗示的要简单。您输入了'юникод',您的编辑器保存了这些字节'\xd1\x8e\xd0\xbd\xd0\xb8\xd0\xba\xd0\xbe\xd0\xb4'(utf-8 中的юникод),python 乖乖地使用cp1251 编码(您已明确指定)解码了这些字节并正确打印了结果(错误的Unicode 字符串) .注意:编码声明 (coding: cp1251) 会被您的编辑器忽略,并且在您的代码中未使用(它用于 Unicode 文字:u'юникод' - 只有在您的编码声明时才有效是正确的——如果磁盘上的字节使用与声明相同的编码)。
  • @J.F.Sebastian:感谢您的参考,我不知道这个模块。但 OP 的问题只是声明 (-*- coding:) 和实际编码之间缺乏连贯性,而不是 显示 任何内容的问题。
【解决方案2】:

您的问题是编码声明错误:您的编辑器使用utf-8 字符编码来保存源代码。 使用# -*- coding: utf-8 -*- 修复它。

>>> u'юникод'
u'\u044e\u043d\u0438\u043a\u043e\u0434'
>>> u'юникод'.encode('utf-8')
'\xd1\x8e\xd0\xbd\xd0\xb8\xd0\xba\xd0\xbe\xd0\xb4'
>>> print _.decode('cp1251') # mojibake due to the wrong encoding
СЋРЅРёРєРѕРґ
>>> print u'юникод'
юникод

不要使用字节串(''literals create bytes object on Python 2)来表示文本; 使用 Unicode 字符串u'' 文字 -- unicode 类型)。 如果您的代码使用 Unicode 字符串,那么您的 Windows 控制台使用的代码页无关紧要,只要所选字体可以显示相应的(非 BMP)字符即可。见Python, Unicode, and the Windows console

这里是完整的代码,供参考:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
print(u'юникод')

注意:没有.decode()unicode()。如果您使用文字来创建字符串;如果字符串包含文本,则应使用 Unicode 文字。它是 Python 3 上唯一不能将非 ascii 字符放入 bytes 文字的选项,这也是 Python 2 上的一个好习惯(使用 Unicode 代替字节字符串)。

如果某些 API 给你一个字节串作为输入(不是字面量),那么它的编码与编码声明无关。使用什么具体的编码取决于数据的来源。

【讨论】:

    【解决方案3】:

    只需使用以下代码,但确保将源代码保存在声明的编码中。它可以是支持您要打印的字符的任何 编码。终端可以采用不同的编码,只要它支持你要打印的字符:

    #coding:utf8
    print u'юникод'
    

    优点是不需要知道终端的编码。 Python通常会1检测终端编码并正确编码打印输出。

    1除非您的终端配置错误。

    【讨论】:

      猜你喜欢
      • 2012-01-13
      • 2021-08-13
      • 1970-01-01
      • 1970-01-01
      • 2017-04-24
      • 2023-03-28
      • 2014-06-24
      • 2020-11-26
      相关资源
      最近更新 更多