在Python中向Unicode字符串添加补充代码点

3 投票
1 回答
842 浏览
提问于 2025-04-17 13:03

unichr(0x10000) 这个命令在没有使用 --enable-unicode=ucs4 选项编译的 cpython 中会失败,并出现 ValueError 错误。

有没有一种语言内置的或者核心库的函数,可以把任意的 unicode 标量值或代码点转换成 unicode 字符串,并且不管程序运行在哪种 Python 解释器上都能正常工作?

1 个回答

8

好的,下面是内容:

>>> unichr(0xd800)+unichr(0xdc00)
u'\U00010000'

关键点是,unichr()这个函数可以把一个整数转换成Python解释器字符串编码中的一个单一字符。根据Python 2.7.3的标准库文档,内置函数部分关于unichr()的说明

它会返回一个单个字符的Unicode字符串,这个字符的Unicode编码是整数i……有效的参数范围取决于Python的配置——可能是UCS2 [0..0xFFFF]或UCS4 [0..0x10FFFF]。否则会抛出ValueError错误。

我特别强调了“单个字符”,这里的意思是在Unicode术语中是“一个代码单元”

我假设你在使用Python 2.x版本。Python 3.x版本没有内置的unichr()函数。相反,Python 3.3.0的标准库文档,内置函数部分关于chr()的说明是:

它会返回一个表示字符的字符串,这个字符的Unicode编码点是整数i……有效的参数范围是从0到1,114,111(0x10FFFF,十六进制表示)。

注意,返回值现在是一个长度不确定的字符串,而不是一个单一代码单元的字符串。所以在Python 3.x中,chr(0x10000)的表现会如你所期待的那样。它“将任意的unicode标量值或编码点转换为一个unicode字符串,这个字符串在任何Python解释器上都能正常工作”。

回到Python 2.x。如果你使用unichr()来创建Python 2.x的unicode对象,并且你使用的Unicode标量值超过0xFFFF,那么你的代码就需要关注Python解释器对unicode对象的实现。

你可以通过一个函数来隔离这种关注,这个函数会尝试对一个标量值使用unichr(),如果捕获到ValueError错误,就会用相应的UTF-16代理对再试一次:

def unichr_supplemental(scalar):
     try:
         return unichr(scalar)
     except ValueError:
         return unichr( 0xd800 + ((scalar-0x10000)//0x400) ) \
               +unichr( 0xdc00 + ((scalar-0x10000)% 0x400) )

>>> unichr_supplemental(0x41),len(unichr_supplemental(0x41))
(u'A', 1)
>>> unichr_supplemental(0x10000), len(unichr_supplemental(0x10000))
(u'\U00010000', 2)

不过你可能会觉得直接把标量值转换成4字节的UTF-32值,然后将这个UTF-32字节string解码成unicode字符串更简单:

>>> '\x00\x00\x00\x41'.decode('utf-32be'), \
... len('\x00\x00\x00\x41'.decode('utf-32be'))
(u'A', 1)
>>> '\x00\x01\x00\x00'.decode('utf-32be'), \
... len('\x00\x01\x00\x00'.decode('utf-32be'))
(u'\U00010000', 2)

上面的代码是在Python 2.6.7上测试的,使用UTF-16编码的Unicode字符串。我没有在使用UTF-32编码的Python 2.x解释器上测试它。不过,它应该在任何Python 2.x解释器和任何Unicode字符串实现上都能正常工作。

撰写回答