使用Python获取字符的Unicode代码点

93

在Python API中,是否有一种方法可以提取单个字符的Unicode代码点?

编辑:如果有影响的话,我正在使用Python 2.7。


1
是的- http://docs.python.org/library/functions.html#ord 可以将'\u304f'转换为'304f'。 - Ken
2
是的,ord("\N{HIRAGANA LETTER KU}") 的确是12367,也就是0x304F。我不会像你这样使用数字来表示字符,只用命名的方式。神奇数字对程序有害。只需要将 chrord 视为互逆函数即可。这很容易理解。 - tchrist
@tchrist 值得注意的是,在Python 3.x中,chrord的相反操作,但在Python 2.x中,unichr才是ord的相反操作,因为在Python 2.x中,chr只对小于等于255的序数起作用。 - cryo
2
@tchrist 仍有很多人使用 Python 2.x。即使在 Python 3.x 中,仍有窄的 Unicode 构建(例如 Python 3.x 的大多数 Windows 构建是窄的)。我不会把大多数 2.x Unicode 问题称为 bug,而更多地是为了保持向后兼容性与旧脚本,Python 2.x 通常可以很好地处理 Unicode。但是Python 3.0确实使事情更加一致,消除了 str 和 unicode 之间的区别。 - cryo
如果c是我的字符变量(假设它等于),如果我执行ucp = ord(c),然后print ucp,我会得到三个整数,而不是一个整数。如何获得一个单一的整数? - Ken
显示剩余2条评论
5个回答

104

如果我正确理解了你的问题,你可以这样做。

>>> s='㈲'
>>> s.encode("unicode_escape")
b'\\u3232'

显示 Unicode 转义代码作为源字符串。


2
如果有关系的话,我正在使用Python 2.7。 - Ken
b 是什么意思? - MK Yung
@MKYung 这个前缀表示这是一个字节字符串的文字。 - Keith
4
对于我来说,ASCII字符不起作用:'a'.encode('unicode_escape') 返回的是 a 而不是 '\u。(u'a'.encode('unicode_escape') 也是一样。) 同样,在超出基本多语言平面时,格式也有所不同:u''.encode('unicode_escape') 得到的是 '\\U0001f631' - ShreevatsaR
4
尝试使用"a".encode("unicode_escape").hex()来获取十六进制表示的字符串。另外,hex(ord("a"))也可以实现相同的效果。 - imrek

73
>>> ord(u"ć")
263
>>> u"café"[2]
u'f'
>>> u"café"[3]
u'\xe9'
>>> for c in u"café":
...     print repr(c), ord(c)
... 
u'c' 99
u'a' 97
u'f' 102
u'\xe9' 233

3
当然,最后可能会打印出 u'e' 101u'\u0301' 769 - Dietrich Epp
3
看起来 'ord()' 可以满足我的需求:http://docs.python.org/library/functions.html#ord。谢谢。 - Ken
如果'c'是我的字符变量(比如它等于'あ'),如果我执行ucp = ord(c),然后print ucp,我会得到三个整数,而不是一个整数。如何获得一个整数? - Ken
如果有关系的话,我正在使用Python 2.7。 - Ken
@mikkokotila您没有提及您的平台或Python版本。不幸的是,细节确实有所不同。在Python 2上,如果您使用u"བཞིན"(而不是"བཞིན"),则不会因为字符大于一个字节而遇到问题 - 但它将把这个字符串视为四个字符,并将 ི 和 ཞ 视为两个不同的字符。我不知道Unicode是否包括藏文的这种组合,就像它为带重音的拉丁语(其中存在单代码点é(u'\xe9')和双代码点é(u'e\u0301'))一样。很抱歉我不能提供更多帮助。 - Mike Graham
显示剩余3条评论

15

结果证明正确地解决这个问题相当棘手:Python 2和Python 3在从字符串中提取Unicode代码点方面存在一些微妙的问题。

直到Python 3.3之前,编译Python有两种模式可选:

  1. sys.maxunicode == 0x10FFFF

在这种模式下,Python的Unicode字符串支持从U+0000到U+10FFFF的完整Unicode代码点范围。一个代码点由一个字符串元素表示:

>>> import sys
>>> hex(sys.maxunicode)
'0x10ffff'
>>> len(u'\U0001F40D')
1
>>> [c for c in u'\U0001F40D']
[u'\U0001f40d']

这是Python 2.7在Linux上的默认设置,也是Python 3.3及以后版本在所有操作系统上的通用设置。

  1. sys.maxunicode == 0xFFFF

在此模式下,Python的Unicode字符串仅支持从U + 0000到U + FFFF的Unicode代码点范围。任何从U + 10000到U + 10FFFF的代码点都使用UTF-16编码中的一对字符串元素表示:

>>> import sys
>>> hex(sys.maxunicode)
'0xffff'
>>> len(u'\U0001F40D')
2
>>> [c for c in u'\U0001F40D']
[u'\ud83d', u'\udc0d']

这是在 macOS 和 Windows 上使用 Python 2.7 的默认设置。

这个运行时差异使得编写 Python 模块来操作 Unicode 字符串作为代码点序列非常不方便。

代码点模块

为了解决这个问题,我贡献了一个新的模块 codepointsPyPI:

https://pypi.python.org/pypi/codepoints/1.0

这个模块通过公开 API 将 Unicode 字符串转换为代码点列表,并从代码点列表转换回 Unicode 字符串,而不考虑 sys.maxunicode 的底层设置来解决这个问题。

>>> hex(sys.maxunicode)
'0xffff'
>>> snake = tuple(codepoints.from_unicode(u'\U0001F40D'))
>>> len(snake)
1
>>> snake[0]
128013
>> hex(snake[0])
'0x1f40d'
>>> codepoints.to_unicode(snake)
u'\U0001f40d'

你好,我正在尝试在Python中使用https://en.wikipedia.org/wiki/Regional_Indicator_Symbol偏移量与代码点来制作各个国家的旗帜。这是一个JavaScript实现:https://github.com/thekelvinliu/country-code-emoji/blob/9d6d20f99f66ef88e01b72f62367e2a950bf1936/src/index.js如何在已通过基本旗帜的适当字母进行偏移的修改代码上使用codepoints.to_unicode(x) - thadk
更新:问题已解决,to_unicode至少需要一个二元组。 - thadk
@thadk,很高兴你解决了问题,但是你能和我分享一下你尝试的第一段代码吗?我很好奇为什么它没有起作用。 - Ben Hamilton
#does not work #print(codepoints.to_unicode(tuple(127462))) #works print(codepoints.to_unicode((127462,))) #works ("AU" Australia Flag) print(codepoints.to_unicode((127462,127482)))``` - thadk

12

通常,您只需执行ord(character)即可找到字符的编码点。但为了完整起见,在Python窄构建中,Unicode补充多语言平面中的宽字符表示为代理对(即两个代码单元),因此在这种情况下,我经常需要做这个小的解决方法:

def get_wide_ordinal(char):
    if len(char) != 2:
        return ord(char)
    return 0x10000 + (ord(char[0]) - 0xD800) * 0x400 + (ord(char[1]) - 0xDC00)

在大多数应用程序中,这种情况很少见,因此通常只需使用ord()


代理对并不是“两个字符”。它代表一个字符,由两个代码点组成。请参阅http://unicode.org/glossary/中的“代码点”和“代码点类型”。 - John Machin
5
你离正确很近,但不完全准确:代理对仍然只是一个码点。它由两个码元组成。 - Thanatos
@Thanatos:你有没有真正阅读我提供的链接?你是否跟进到“D71高代理代码点:Unicode代码点范围在U+D800到U+DBFF之间。”以及低等效的D73? - John Machin
1
@JohnMachin:标准使用这种术语有点令人困惑。我想在某些方面,它们是代码点 - 这些范围内的代码点保留用于代理对。我认为标准只是在表明代码点已被保留。请注意,“高代理项和低代理项代码点指定为UTF-16字符编码形式中的代理代码单元。它们未分配给任何抽象字符。” - Thanatos
1
我的观点是,代理对一旦解码,就代表一个单独的代码点。只有两件事情:编码的UTF-16代码单元流或解码的代码点流;对于代理对,前者有2个,后者有1个。 - Thanatos

5

python2

>>> print hex(ord(u'人'))
0x4eba

要获取整数值:int(hex(ord(u'人')),16) - undefined

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