tl;dr:使用\X
正则表达式提取用户感知的字符:
>>> import regex # $ pip install regex
>>> regex.findall(u'\\X', u'เมื่อแรกเริ่ม')
['เ', 'มื่', 'อ', 'แ', 'ร', 'ก', 'เ', 'ริ่', 'ม']
虽然我不会泰语,但我会一点法语。
考虑这封信è
。在 Python shell 中让s
和s2
等于:è
>>> s
'è'
>>> s2
'è'
同一个字母?在视觉上对讲法语的人来说,oui。对于计算机,否:
>>> s==s2
False
您可以使用实际的代码点创建相同的字母,也可以è
通过获取字母e
并添加添加该重音字符的组合代码点来创建相同的字母。它们有不同的编码:
>>> s.encode('utf-8')
b'\xc3\xa8'
>>> s2.encode('utf-8')
b'e\xcc\x80'
和不同的长度:
>>> len(s)
1
>>> len(s2)
2
但从视觉上看,两种编码都会产生 'letter' è
。这称为字形,或最终用户认为的一个字符。
您可以演示您看到的相同循环行为:
>>> [c for c in s]
['è']
>>> [c for c in s2]
['e', '̀']
您的字符串中有几个组合字符。因此,你眼中的 9 个字素字符的泰语字符串在 Python 中变成了 13 个字符的字符串。
法语的解决方案是基于 Unicode equivalence规范化字符串:
>>> from unicodedata import normalize
>>> normalize('NFC', s2) == s
True
但是,这不适用于许多非拉丁语言。处理可能是组成单个字素的多个代码点的 unicode 字符串的一种简单方法是使用正则表达式引擎,该引擎通过支持\X
. 不幸的是,Python 的包含re
模块还没有。
建议的替代品regex确实支持\X
:
>>> import regex
>>> text = 'เมื่อแรกเริ่ม'
>>> regex.findall(r'\X', text)
['เ', 'มื่', 'อ', 'แ', 'ร', 'ก', 'เ', 'ริ่', 'ม']
>>> len(_)
9