Python中Unicode是如何内部表示的?

23

Python中Unicode字符串在内存中如何表示?

例如,我可以将'abc'视为其在内存中等效的ASCII字节。整数可以认为是2的补码表示。然而,即使在UTF-8中以'\xe2\x81\x89'(3个字节)表示,u'\u2049'的文字代码点在内存中该如何表示?

它是否有特定的存储方式?Python 2和Python 3是否有不同的处理方式?

其他几个相关问题:

1)这些字符串在Python解释器中是如何表示的?我不理解。

2)Python 3.x中字符串的内部表示是什么?

1个回答

28

我假设您想了解CPython,即标准实现。Python 2和Python 3.0-3.2使用UCS2*或UCS4来表示Unicode字符,这意味着每个字符将使用2个或4个字节。选择哪个是编译时的选项。

\u2049 然后表示为 \x49\x20\x20\x49\x49\x20\x00\x00\x00\x00\x20\x49,取决于您系统的本地字节顺序以及是否选择了UCS2或UCS4。 Unicode字符串中的ASCII字符仍然每个字符占用2或4个字节。

Python 3.3切换到了新的内部表示形式,使用最紧凑的形式来表示字符串中的所有字符。会选择1个字节、2个字节或4个字节。 ASCII和Latin-1文本每个字符只使用1个字节,其余BMP字符需要2个字节,之后使用4个字节。

参见PEP-393:Flexible String Representation获取有关这些表示的完整信息。


* 严格来说,UCS-2构建使用UTF-16,因为非BMP字符使用UTF-16代理项将每个字符编码为4个字节(2个UTF-16字符)。但是,Python文档仍将其称为UCS2。

这会导致意外的行为,例如非BMP Unicode字符串上的 len()比包含的字符数更长。


2
要知道你是否有一个“窄”(UCS2)或“宽”(UCS4)的构建,请检查sys.maxunicode。65535表示窄,1114111表示宽。 - Ned Batchelder
1
我认为从技术上讲,它应该是UTF-16或UTF-32,而不是UCS2或UCS4,因为在窄版本中使用了代理对,使其成为UTF-16。 - Ned Batchelder
@NedBatchelder:确实,不确定为什么文档仍然坚持使用UCS。 - Martijn Pieters
你是在说len()函数不是计算字符串中Unicode码点的数量,而是计算字符串在内存中的编码长度吗? - undefined
@Joe:不是的,字符串对象在一个变量中存储Unicode点的数量,而len()函数返回该变量的值。然而,在旧版本的Python(不再受支持)中,使用UCS2编码时,如果存储了一个非BMP码点,那么它们将被计为两个字符而不是一个。例如,len(u"\U0001D49E")(或len(u"\N{MATHEMATICAL SCRIPT CAPITAL C}"))在这些版本中返回2,因为在UCS2中,该码点由\ud835\udc9e表示。 - undefined
显示剩余4条评论

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