如何在Python中获得组合Unicode字符串的"可见"长度?

oro*_*ome 11 python unicode python-2.7

如果我有一个包含组合字符的Python Unicode字符串,则len报告的值与"看到"的字符数不对应.

例如,如果我有结合overlines的字符串,并强调如u'A\u0332\u0305BC',len(u'A\u0332\u0305BC')报告5; 但显示的字符串长度只有3个字符.

如何获得"可见" - 即用户看到的字符串占用的不同位置的数量 - 包含Python中组合字形的Unicode字符串的长度?

daw*_*awg 5

如果您有支持匹配字素的正则表达式风格,您可以使用\X

演示

虽然默认的 Python re 模块不支持\X,但 Matthew Barnett 的regex 模块支持:

>>> len(regex.findall(r'\X', u'A\u0332\u0305BC'))
3
Run Code Online (Sandbox Code Playgroud)

在 Python 2 上,您需要u在模式中使用:

>>> regex.findall(u'\\X', u'A\u0332\u0305BC')
[u'A\u0332\u0305', u'B', u'C']
>>> len(regex.findall(u'\\X', u'A\u0332\u0305BC'))
3
Run Code Online (Sandbox Code Playgroud)


Mar*_*som 4

unicodedata模块combining具有可用于确定单个字符是否为组合字符的功能。如果它返回,0您可以将该字符算作非组合字符。

import unicodedata
len(u''.join(ch for ch in u'A\u0332\u0305BC' if unicodedata.combining(ch) == 0))
Run Code Online (Sandbox Code Playgroud)

或者,稍微简单一点:

sum(1 for ch in u'A\u0332\u0305BC' if unicodedata.combining(ch) == 0)
Run Code Online (Sandbox Code Playgroud)

编辑:正如评论中所指出的,除了组合标记之外,还有一些代码点可以修改字符,而不是本身不应该在计数中的字符。这是上述内容的更强大的版本:

modifier_categories = set(['Mc', 'Mn'])
sum(1 for ch in u'A\u0332\u0305BC' if unicodedata.category(ch) not in modifier_categories)
Run Code Online (Sandbox Code Playgroud)

我们可以使用另一个 Python 技巧,利用True==1和来使事情变得更简单False==0

sum(unicodedata.category(ch) not in modifier_categories for ch in u'A\u0332\u0305BC')
Run Code Online (Sandbox Code Playgroud)

  • 这不适用于由非标记字符组成的字素簇,例如:`u'\u1100\u1161\u11A8'` (각)。 (3认同)