Учитывая список кодовых точек Unicode, как можно разделить их на список символов Unicode?

Я пишу лексический анализатор для текста Unicode. Многие символы Юникода требуют нескольких кодовых точек (даже после канонической композиции). Например, tuple(map(ord, unicodedata.normalize('NFC', 'ā́'))) оценивает (257, 769), Как я могу узнать, где находится граница между двумя символами? Кроме того, я хотел бы сохранить ненормализованную версию текста. Мой вход гарантированно будет Unicode.

Пока что вот что у меня есть:

from unicodedata import normalize

def split_into_characters(text):
    character = ""
    characters = []

    for i in range(len(text)):
        character += text[i]

        if len(normalize('NFKC', character)) > 1:
            characters.append(character[:-1])
            character = character[-1]

    if len(character) > 0:
        characters.append(character)

    return characters

print(split_into_characters('Puélla in vī́llā vīcī́nā hábitat.'))

Это неправильно печатает следующее:

['P', 'u', 'é', 'l', 'l', 'a', ' ', 'i', 'n', ' ', 'v', 'ī', '́', 'l', 'l', 'ā', ' ', 'v', 'ī', 'c', 'ī', '́', 'n', 'ā', ' ', 'h', 'á', 'b', 'i', 't', 'a', 't', '.']

Я ожидаю, что это напечатает следующее:

['P', 'u', 'é', 'l', 'l', 'a', ' ', 'i', 'n', ' ', 'v', 'ī́', 'l', 'l', 'ā', ' ', 'v', 'ī', 'c', 'ī́', 'n', 'ā', ' ', 'h', 'á', 'b', 'i', 't', 'a', 't', '.']

2 ответа

Решение

Границы между воспринимаемыми символами можно определить с помощью алгоритма Unicode Grapheme Cluster Boundary Boundary. Питона unicodedata модуль не имеет необходимых данных для алгоритма (Grapheme_Cluster_Break свойство), но полные реализации можно найти в таких библиотеках, как PyICU а также uniseg,

Вы можете использовать библиотеку pyuegc , реализацию алгоритма Unicode для разбиения последовательностей кодовых точек на расширенные кластеры графем, как указано в UAX #29.

      from pyuegc import EGC  # pip install pyuegc

string = 'Puélla in vī́llā vīcī́nā hábitat.'
egc = EGC(string)
print(egc)
# ['P', 'u', 'é', 'l', 'l', 'a', ' ', 'i', 'n', ' ', 'v', 'ī́', 'l', 'l', 'ā', ' ', 'v', 'ī', 'c', 'ī́', 'n', 'ā', ' ', 'h', 'á', 'b', 'i', 't', 'a', 't', '.']

print(len(string))
# 35
print(len(egc))
# 31
Другие вопросы по тегам