Python中的Unicode - 仅限UTF-16?

10

在我的Python世界中,我很高兴知道当我需要向用户输出内容时,把所有内容都编码成Unicode并编码为UTF-8。然后,我的一个同事发送给我一篇文章“The UTF-8 Everywhere' manifesto”(2012年),它让我感到困惑。

  • 文章的作者多次声称UCS-2 Unicode表示法与Python使用的UTF-16是相同的。
    • 他甚至直接说Python在内部字符串表示上使用UTF-16。
  • 这位作者也承认自己是个Windows爱好者和开发人员,他指出微软多年来处理字符编码的方式导致该群体最困惑,也许只是他自己感到困惑。 我不知道...

请问有人能解释Python中UTF-16和Unicode的状态吗? 它们是否相同,如果不是,请说明差异在哪里?


1
你为什么关心Python的“内部”字符串表示?该网站的重点是说服开发人员在编写的所有代码中使用UTF-8 - 而你不是正在开发Python内部,对吗? - Matt Ball
1
UCS-2和UTF-16并不相同。UCS-2已经过时,因为它不能编码所有的Unicode代码点。 - Mark Ransom
1
@MattBall SO是关于开发者分享知识(并互相帮助)的平台。这正是我感兴趣的事情。难道我需要更多的理由来提出这个问题吗? - Endophage
@MarkRansom如果您愿意发布包括您在下面评论中的观点和这一点的答案,我很乐意给您一个赞。 - Endophage
1
你读过《每个软件开发者绝对必须了解的Unicode和字符集入门知识(不容忽视!)》吗?链接:http://www.joelonsoftware.com/articles/Unicode.html - user395760
显示剩余3条评论
1个回答

23

在Python(2.2到3.2版本)中,Unicode字符串的内部表示取决于Python是否以模式编译。大多数Python构建是窄的(您可以使用sys.maxunicode检查-在窄构建上为65535,在宽构建上为1114111)。

使用宽构建,字符串在内部是由4字节宽字符序列组成,即它们使用UTF-32编码。所有代码点都恰好是一个宽字符长度。

使用窄构建,字符串在内部是由2字节宽字符序列组成,使用UTF-16。超出BMP(代码点U+10000及以上)的字符使用通常的UTF-16代理对存储:

>>> q = u'\U00010000'
>>> len(q)
2
>>> q[0]
u'\ud800'
>>> q[1]
u'\udc00'
>>> q
u'\U00010000'
注意,UTF-16和UCS-2不是相同的编码方式。UCS-2是一种固定宽度编码:每个代码点编码为2个字节。因此,UCS-2 无法 编码超出BMP范围的码位。UTF-16是一种可变宽度编码;BMP之外的码位使用由一对字符组成的代理对进行编码。
请注意,在3.3版本中,由于实现了PEP 393,所有这些都发生了改变。现在,Unicode字符串使用足够宽的字符来表示最大的代码点--8位ASCII字符串,16位BMP字符串,否则为32位。这消除了宽/窄的分界,并在许多仅包含ASCII字符串的情况下有助于减少内存使用。

4
在3.3版本中,他们引入了一种更加灵活的方案,其中每个字符的大小由字符串中最大的代码点确定。ASCII字符串每个字符只有8位,不再有宽窄模式。 - Mark Ransom
谢谢。我修改了我的答案,包括这些细节。(当您发表评论时,我正在阅读相关PEP :)) - nneonneo
所以如果我理解你的意思正确的话,它实际上是一个混合表示内部。UCS-2覆盖BMP,然后UTF-16超出这个范围。然而,Python仍然称其为“Unicode”。是吗? - Endophage
2
在3.3之前,它是纯粹的UTF-16 / UTF-32。在3.3中,它是“UCS-1”,UCS-2和UCS-4的混合体。 - nneonneo
抱歉,当我遇到其他信息时,我删除了那个评论。是的,UTF-16是UCS-2的超集。感谢提供信息! - Endophage
显示剩余2条评论

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