字符串——Unicode 字符串

未匹配的标注

Python的字符串还带有在国际化字符集中处理文本所需的完整Unicode支持。比如,日语和俄语的字母表中的字符就在ASCII集之外。这些非ASCII文本可以显示在网页,电子邮件,图形用户界面,JSON,XML或其他地方。当它出现时,处理好它就需要Unicode支持。Python内置了这些支持,但不同Python产品线的Unicode支持的形式也不同,并且这是他们最明显的差异之一。

在Python 3.X中,普通的 str 字符串处理Unicode文本(包括ASCII,它只是一种简单的Unicode);明显不同的 bytes 字符串类型表示原始字节值(包括媒体和编码过的文本);并且为了兼容2.X,2.X的Unicode字面量在3.3和之后版本中被支持(它们和普通的3.X str 字符串处理方式相同):

>>> 'sp\xc4m' # 3.X: 普通 `str` 字符串是Unicode 文本
'spÄm'
>>> b'a\x01c' # 字节字符串是基于字节的数据
b'a\x01c'
>>> u'sp\u00c4m' # 2.X Unicode 字面量适用于3.3+:只是字符串
'spÄm'

在Python 2.X中,普通的 str 字符串处理8位字符串(包括ASCII文本)和原始字节值;明显不同的 unicode 字符串类型表示Unicode文本;并且为了兼容3.X,3.X的字节字面量在2.6和之后的版本中被支持(它们和普通2.X str 字符串处理方式相同):

>>> print u'sp\xc4m' # 2.X: Unicode 字符串是一个不同的类型
spÄm
>>> 'a\x01c' # 普通的 `str` 字符串包含基于字节的文本/数据
'a\x01c'
>>> b'a\x01c' # 3.X 字节字面量在2.6+中可用:只是字符串
'a\x01c'

规范的说,在2.X和3.X中,非Unicode字符串都是8位字节的序列,在可能的情况下使用ASCII字符打印,而Unicode字符串是Unicode 码点(字符的识别数字,当编码到文件或存储到内存中时不一定映射到单字节)的序列。事实上,字节的概念不适用于Unicode:一些编码包括对一个字节太大的字符码点,而且在一些编码和内存存储方案下,甚至简单的7位ASCII文本也不是每个字符串存储一个字节:

>>> 'spam' # 在内存中,字符可以为1,2或4个字节
'spam'
>>> 'spam'.encode('utf8') # 在文件中,以UTF-8编码为4个字节
b'spam'
>>> 'spam'.encode('utf16') # 但在UTF-16中编码为10个字节
b'\xff\xfes\x00p\x00a\x00m\x00'

3.X 和 2.X 都支持我们之前见过的 bytearray 字符串类型,它本质上是一个bytes 字符串(在 2.X中是 str),支持列表对象的大多数就地可变更改操作。

3.X和2.X也都支持使用 \x 十六进制和短 \u和长\UUnicode转义,还有在程序源文件中声明的文件级编码。下面是在3.X中非ASCII字符编码的三种方式(在2.X中添加一个前导“u”并说“print”效果相同):

>>> 'sp\xc4\u00c4\U000000c4m' # 3.X
'spÄÄÄm'
>>> print u'sp\xc4\u00c4\U000000c4m' # 2.X
spÄÄÄm

这些值的含义和它们的使用方式在文本字符串(3.X中是普通字符串,而2.X中是Unicode)和字节字符串(3.X中是字节,而2.X中是普通字符串)之间是不同的。所有这些转义都能被用来嵌套真正的Unicode码点序列值整数到文本字符串中。作为对比,字节字符串只使用 \x十六进制转义来嵌套文本的编码形式,而不是它的解码的码点值——只有对某些编码和字符,编码字节和码点是相同的:

>>> '\u00A3', '\u00A3'.encode('latin1'), b'\xA3'.decode('latin1')
('£', b'\xa3', '£')

作为一个显著的区别,只要普通字符串中的字符全是ASCII,Python 2.X 允许它的普通字符串和Unicode字符串在表达式中混合;作为对比,Python 3.X有一个更严格的模型,它从不允许它的普通字符串和字节字符串未经明确的转换而混合:

u'x' + b'y' # 在 2.X 中可行(其中 b 可选且被忽略)
u'x' + 'y' # 在2.X 中可行: u'xy'

u'x' + b'y' # 在 3.3 中出错(其中 u 可选且被忽略)
u'x' + 'y' # 在 3.3 中可行: 'xy'

'x' + b'y'.decode() # 如果解码字节为字符串:'str',则在3.X中可行
'x'.encode() + b'y' # 如果编码字符串为字节,则在3.X中可行:b'xy'

除了这些字符串类型,Unicode处理主要集中在文件中来回传输文本数据——当存储到文件时,文本是被编码为字节,当读取回内存时是被解码为字符(也就是码点)。一旦文本被加载到内存中,通常只将它作为解码形式的字符串来处理。

但是,由于这个模型,在3.X中文件也是特定于内容的:文本文件实现指定名称的编码和接收和返回 str 字符串,但二进制文件对于原始二进制数据用 bytes 字符串来处理。在Python 2.X中,普通文件的内容是 str 字节,一个特殊的 codecs 模块处理Unicode和使用 unicode 类型表示内容。

在本章稍后将再次见到文件中的Unicode,但将Unicode故事的剩余部分留在本书后面。它在第25章的一个与货币符号相关的例子中简短地出现,但大部分内容被推迟到本书的高级主题部分。Unicode在一些领域十分重要,但许多程序员只是有基本的了解也能勉强应付过去。如果数据全是ASCII文本,字符串和文件的主题在2.X和3.X中基本都是相同的。并且如果是编程新手,可以安全地推迟大多数Unicode细节直到已经精通了字符串基础。

本节思维导图

image-20230113210204141

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
讨论数量: 0
发起讨论 只看当前版本


暂无话题~