Python的len()函数按Unicode码点计数,导致泰米尔语等复杂文字显示长度异常;需使用支持Unicode图形单元(grapheme)的regex模块替代内置re,才能获得符合人类直觉的字符数。
python的`len()`函数按unicode码点计数,导致泰米尔语等复杂文字显示长度异常;需使用支持unicode图形单元(grapheme)的`regex`模块替代内置`re`,才能获得符合人类直觉的字符数。
在处理多语言文本时,尤其是印度系文字(如泰米尔语、梵文、印地语)或带变音符号的欧洲语言(如法语 café),直接调用 len() 常会返回“意外”的结果。例如:
>>> len('KUMAR') # ASCII字母,每个字符对应1个码点
5
>>> len('குமார்') # 泰米尔语,输出为6而非直观的3
6
这是因为 'குமார்' 实际由 6个Unicode码点 构成:
- க் = U+0B95(辅音“ka”) + U+0BCD(辅音抑制符 pulli)
- ு = U+0BC1(短元音符号 u-kurru)
- மா = U+0BAE(辅音“ma”) + U+0BBE(长元音符号 aa-kurru)
- ர் = U+0BB0(辅音“ra”) + U+0BCD(pulli)
这些组合共同构成 3个视觉上独立的图形单元(graphemes) —— 即人类阅读时感知的“一个字”。
✅ 正确解法:使用支持Unicode图形单元切分的 regex 模块(非标准库 re):
pip install regex
import regex
def count_graphemes(text):
"""返回字符串中Unicode图形单元(用户感知的‘字符’)数量"""
return len(regex.findall(r'\X', text)) # \X 匹配单个grapheme cluster
# 测试对比
english_name = 'KUMAR'
tamil_name = 'குமார்'
print(f"Length of '{english_name}': {count_graphemes(english_name)}") # → 5
print(f"Length of '{tamil_name}': {count_graphemes(tamil_name)}") # → 3
⚠️ 注意事项:
- 不要使用 re.findall(r'.', text, re.UNICODE) —— 它仍按码点匹配,无法识别组合规则;
- regex 模块的 \X 是专为 grapheme cluster 设计的正则原子,遵循 Unicode Standard Annex #29 规范;
- 对于其他复杂文字(如阿拉伯语连字、越南语多声调组合、Emoji ZWJ序列 ??),该方法同样适用。
总结:len() 统计的是底层编码单元(code points),而真实应用中我们通常需要统计用户可见的“字”(graphemes)。切换至 regex 模块并使用 \X,是解决多语言字符串长度误判最可靠、跨语言兼容的标准方案。











