Алгоритм разбиения текста на графемные кластеры приведен в Unicode Annex 29 , раздел 3.1. Я не собираюсь реализовывать здесь полный алгоритм для вас, но я покажу вам, как обращаться со случаем Деванагари, а затем вы сможете прочитать Приложение для себя и посмотреть, что еще вам нужно реализовать.
Модуль unicodedata
содержит информацию, необходимую для обнаружения кластеров графем.
>>> import unicodedata
>>> a = "बिक्रम मेरो नाम हो"
>>> [unicodedata.name(c) for c in a]
['DEVANAGARI LETTER BA', 'DEVANAGARI VOWEL SIGN I', 'DEVANAGARI LETTER KA',
'DEVANAGARI SIGN VIRAMA', 'DEVANAGARI LETTER RA', 'DEVANAGARI LETTER MA',
'SPACE', 'DEVANAGARI LETTER MA', 'DEVANAGARI VOWEL SIGN E',
'DEVANAGARI LETTER RA', 'DEVANAGARI VOWEL SIGN O', 'SPACE',
'DEVANAGARI LETTER NA', 'DEVANAGARI VOWEL SIGN AA', 'DEVANAGARI LETTER MA',
'SPACE', 'DEVANAGARI LETTER HA', 'DEVANAGARI VOWEL SIGN O']
В Деванагари каждый кластер графем состоит из начальной буквы, необязательных пар virama (убийца гласных) и буквы и необязательного знака гласной. В регулярных выражениях это будет LETTER (VIRAMA LETTER)* VOWEL?
. Вы можете узнать, что есть что, посмотрев категорию Unicode для каждой кодовой точки:
>>> [unicodedata.category(c) for c in a]
['Lo', 'Mc', 'Lo', 'Mn', 'Lo', 'Lo', 'Zs', 'Lo', 'Mn', 'Lo', 'Mc', 'Zs',
'Lo', 'Mc', 'Lo', 'Zs', 'Lo', 'Mc']
Буквы относятся к категории Lo
(Буква, Другое), гласные - к категории Mc
(Марк, объединение пробелов), virama - к категории Mn
(Марка, без пробелов), а пробелы относятся к категории Zs
(Разделитель, Space).
Итак, вот грубый подход к разделению кластеров графемы:
def splitclusters(s):
"""Generate the grapheme clusters for the string s. (Not the full
Unicode text segmentation algorithm, but probably good enough for
Devanagari.)
"""
virama = u'\N{DEVANAGARI SIGN VIRAMA}'
cluster = u''
last = None
for c in s:
cat = unicodedata.category(c)[0]
if cat == 'M' or cat == 'L' and last == virama:
cluster += c
else:
if cluster:
yield cluster
cluster = c
last = c
if cluster:
yield cluster
>>> list(splitclusters(a))
['बि', 'क्र', 'म', ' ', 'मे', 'रो', ' ', 'ना', 'म', ' ', 'हो']