Учитывая список кодовых точек 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