【问题标题】:Encoding a unicode string to utf-8 and getting question marks将 unicode 字符串编码为 utf-8 并获取问号
【发布时间】:2015-01-22 01:09:00
【问题描述】:

系统:

Python 2.7.5 , IPython 2.3.1 , OSX terminal (local), sys.stdout.encoding : 'UTF-8'
(venv) toz$ locale LANG="en_US.UTF-8" LC_COLLATE="en_US.UTF-8" LC_CTYPE="en_US.UTF-8" LC_MESSAGES="en_US.UTF-8" LC_MONETARY="en_US.UTF-8" LC_NUMERIC="en_US.UTF-8" LC_TIME="en_US.UTF-8" LC_ALL= –

我希望两个命令打印相同,但后者打印 ord(c)>128 的问号。这是为什么?如何编码这个 unicode 字符串并在不得到问号的情况下进行迭代?

In [77]: for c in u'!"#%\'()*+,-./:;<=>?@[\]^_`{|}~’”“': print c.encode('utf-8'),
! " # % ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` { | } ~ ’ ” “

In [78]: for c in u'!"#%\'()*+,-./:;<=>?@[\]^_`{|}~’”“'.encode('utf-8'): print c,
! " # % ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` { | } ~ ? ? ? ? ? ? ? ? ?

让我们打印 ord 值:

In [92]: for c in u'!"#%\'()*+,-./:;<=>?@[\]^_`{|}~’”“': print c.encode('utf-8'),ord(c),
! 33 " 34 # 35 % 37 ' 39 ( 40 ) 41 * 42 + 43 , 44 - 45 . 46 / 47 : 58 ; 59 < 60 = 61 > 62 ? 63 @ 64 [ 91 \ 92 ] 93 ^ 94 _ 95 ` 96 { 123 | 124 } 125 ~ 126 ’ 8217 ” 8221 “ 8220

In [93]: for c in u'!"#%\'()*+,-./:;<=>?@[\]^_`{|}~’”“': print c.encode('utf-8'),ord(c.encode('utf-8')),
! 33 " 34 # 35 % 37 ' 39 ( 40 ) 41 * 42 + 43 , 44 - 45 . 46 / 47 : 58 ; 59 < 60 = 61 > 62 ? 63 @ 64 [ 91 \ 92 ] 93 ^ 94 _ 95 ` 96 { 123 | 124 } 125 ~ 126 ’---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-93-1eb3985b825b> in <module>()
----> 1 for c in u'!"#%\'()*+,-./:;<=>?@[\]^_`{|}~’”“': print c.encode('utf-8'),ord(c.encode('utf-8')),

TypeError: ord() expected a character, but string of length 3 found

我可以将三到九个问号的长度以及三个非 ascii 字符中的每一个所需的(三个)字节联系起来。

【问题讨论】:

  • 启动 ipython notebook 以获取 Web 界面并避免 Unicode + Windows 控制台问题。在这种情况下打印 Unicode(删除 .encode('utf-8'))。
  • 如果您不在 Windows 上;要修复输出,只需删除 .encode('utf-8')(直接打印 Unicode)。
  • 我在 OSX 上,也从 ipython notebook 获得了相同的输出(即问号)。
  • 你有没有像我说的那样放弃.encode('utf-8')?添加assert type(c) == unicode

标签: python unicode utf-8


【解决方案1】:

当您encode 一个字符串时,它会从 Unicode 字符转换为字节。每个字符可以成为可变数量的字节。您的控制台似乎将 0-127 的 ASCII 范围之外的任何字节打印为问号。

>>> for c in u'!"#%\'()*+,-./:;<=>?@[\]^_`{|}~’”“': print len(c.encode('utf-8')),

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 3


>>> for c in u'!"#%\'()*+,-./:;<=>?@[\]^_`{|}~’”“'.encode('utf-8'): print c,ord(c),

! 33 " 34 # 35 % 37 ' 39 ( 40 ) 41 * 42 + 43 , 44 - 45 . 46 / 47 : 58 ; 59 < 60 = 61 > 62 ? 63 @ 64 [ 91 \ 92 ] 93 ^ 94 _ 95 ` 96 { 123 | 124 } 125 ~ 126 â 226 タ 128 ル 153 â 226 タ 128 ン 157 â 226 タ 128 ワ 156

你得到问号的原因是你已经分解了 UTF-8 序列,并且序列的每个字节都不是一个有效的字符本身。这些无效字符显示为问号。

如您所见,我的控制台(Python 2.7.5 的 IDLE)不打印问号,而是用不正确的字符代替。

【讨论】:

  • 它应该打印3 而不是2。我已经从您的答案u'’”“' 中复制粘贴了字符,它们是u'\u2019\u201d\u201c'。任何其他值都是您的环境的问题。 U+0092 等是与引号无关的控制字符。
  • @J.F.Sebastian 我在两台不同的 PC 上得到了相同的结果,它们都运行 Windows 7,从 Chrome 复制并粘贴到 Python 2.7 IDLE 控制台。
  • 您可以在将它们发送到子进程时检查它是否是 Windows 剪贴板损坏了值(不太可能)或 IDLE:print repr(u'\u2019\u201d\u201c'), u'\u2019\u201d\u201c'。如果 Python 2 上的 IDLE 支持它;尝试使用“相同/单进程”模式启动它。
  • u'\u2019'.encode('cp1252').decode('latin1') == u'\x92'
  • @J.F.Sebastian 问题出在空闲,如果我直接从剪贴板读取字符,我会得到正确的值。
【解决方案2】:

您似乎有“C”语言环境。您可以使用locale shell 命令检查它。 或者您可以使用 LANG=en_US.UTF-8 ipython 运行 ipython(用于 bash/sh/etc)

【讨论】:

  • 似乎与语言环境无关:(venv) toz$ locale LANG="en_US.UTF-8" LC_COLLATE="en_US.UTF-8" LC_CTYPE="en_US.UTF-8" LC_MESSAGES="en_US.UTF-8" LC_MONETARY="en_US.UTF-8" LC_NUMERIC="en_US.UTF-8" LC_TIME="en_US.UTF-8" LC_ALL=
  • 我猜这是一个 ssh 会话。然后问题出在终端的设置中。你用腻子?
  • 你使用 Terminal.app 吗?试试 iTerm2。这是一个非常有趣的问题。
  • 是的,普通终端。我在笔记本上也得到了同样的结果:screenshot
  • 最后的猜测。 sys.stdout.encoding 有什么价值?
猜你喜欢
  • 1970-01-01
  • 2011-08-09
  • 2013-06-27
  • 2014-01-18
  • 2011-08-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多