LIBMORPH API
Модули libmorph* используют единые программные интерфейсы – multibyte IMlmaMb
с поддержкой различных кодовых страниц (1251, koi8, 866, Mac, utf-8) и widechar IMlmaWc
с кодировкой UTF-16.
Выбор кодовой страницы для работы модуля выполняется в момент запроса интерфейса передачей строки-идентификатора.
Интерфейсы декларированы в форме, обеспечивающей доступность из приложений на языке C. Однако для простоты восприятия здесь они приведены как классы C++.
Устройство словаря
Модель описания словоизменения
Радиксное дерево
Сканирование словаря
Программный интерфейс
Структуры данных
Грамматика словоформы
Найденная лексема
Интерфейс находок по шаблону
IMlmaMb и IMlmaWc
Функции
Проверка правописания
Лемматизация
Построение формы слова
Построение форм возможных лексем
Информация о лексеме
Поиск по шаблону
CXX-расширение
Устройство словаря
Модель описания словоизменения
Для описания словоизменения слово, точнее, его нормальная форма, представленная в словнике, разбивается на три фрагмента:
- псевдооснова - неизменяемая графическая последовательность;
- чередующаяся часть основы;
- окончание.
Окончание при генерации словаря отщепляется автоматически в соответствии с грамматической информацией, содержащейся в таблице окончаний, приписанной данному слову. В случае, если в основе слова есть чередования, то определяется, какой фрагмент чередуется с каким (подбирается таблица чередований в основе), а от основы отщепляется фрагмент чередования, соответствующий нормальной форме слова.
В перечисленных ниже примерах чередующийся фрагмент основы выделен жирным шрифтом, а окончание - косым:
- кош-к-а - кош-ек
- кноп-к-а - кноп-ок
- ос-ел - ос-л-а
- л-ед - л-ьд-а
- в-обр-ать - в-бер-у
Для каждого слова после отщепления всех изменяемых частей в словарь заносится часть речи, ссылка на таблицу чередований в основе (если есть) и ссылка на таблицу окончаний. При работе анализатора нужная ступень чередования выбирается по жестким формальным правилам, которые в этом документе не приводятся.
Радискное дерево

Словарь представляет собою дерево, в каждом узле которого находится таблица, ставящая в соответствие каждому символу смещение аналогичной таблицы следующего уровня. А результате поис строки сводится к нескольким побайтовым сравнениям в памяти – это основное достоинство префиксного дерева, позволяющее получать производительность хэш-таблиц при сохранении возможности лексикографической итерации. Радиксное дерево делает ещё шаг в сторону компактизации словаря, схлопывая узлы с единственной исходящей веткой вр фрагмент строки.
Пусть словарь содержит лишь слова "стол", "столешница", "стоять", "стоить", "стрелять", "судить" и "ты". Тогда, после отщепления всех изменчивых фрагментов, мы получим (в порядке следования) графические псевдоосновы "стол", "столешниц", "сто", "сто", "стрел", "су" и "т". Дерево, строящееся из них, можно представить следующим образом:
Под "грамматической информацией" следует понимать в данном случае часть речи, ссылку на таблицу чередований в основе, ссылку на таблицу окончаний и список чередующихся приставок.
Сканирование словаря
При сканировании устроенного таким образом словаря фактически идет перебор элементов таблицы очередного уровня (0 - для первой буквы слова, 1 - для второй и т. д). Рассмотрим этот процесс на примере изображенного выше мини-словарика.
Пусть на обработку поступило слово "суд". Находясь в корне дерева, мы можем утверждать, что если такое слово в словаре есть, то оно находится на ветви, начинающейся от буквы "с".
Переходим на второй уровень. Теперь текущая буква слова – "у". Допустимые буквы после "с" в нашем примере – "т" и "у". Если искомое слово в словаре есть, оно лежит на ветви дерева, на которую ссылается буква "у".
На третьем уровне таблица пуста, что означает, что возможно лишь отождествление по окончаниям. Понятно, что на таблице чередований "д/ж/ж" (судить - сужу - суженный) и таблице окончаний глагола "су-д-ить" слово "суд" отождествиться не может.
Программный интерфейс
Структуры данных
Грамматика словоформы
struct SGramInfo
{
unsigned char wInfo;
unsigned char iForm;
unsigned short gInfo;
unsigned char other;
};
struct SGramInfo { unsigned char wInfo; unsigned char iForm; unsigned short gInfo; unsigned char other; };
Для полного грамматического описания формы слова используется структура SGramInfo, в которой:
wInfo– техническая часть речи;gInfo– грамматическое описание;iForm– идентификатор формы слова, соответствующий грамматике для данной части речи;other– дополнительные признаки одушевленности (0x01) и неодушевленности (0x02).
Найденная лексема
struct SLemmInfoA { lexeme_t nlexid; const char* plemma; SGramInfo* pgrams; unsigned ngrams; } SLemmInfoA; struct SLemmInfoW { lexeme_t nlexid; const widechar* plemma; SGramInfo* pgrams; unsigned ngrams; };
Две структуры описывают отождествления одной лексемы при лемматизации, однако первая из них используется в multibyte-, а вторая - в unicode-интерфейсе при вызове функции лемматизации. В этих структурах:
nlexid- уникальный идентификатор лексемы;plemma- словарная форма или NULL, если построение словарных форм не требуется;pgrams- грамматические описания отождествлений или NULL, если не требуются;ngrams- количество грамматических описаний.
Интерфейс находок по шаблону
struct SStrMatch { union { const char* sz; const widechar* ws; }; size_t cc; formid_t id; }; struct IMlmaMatch { int Attach(); int Detach(); int AddLexeme( lexeme_t nlexid, int nforms, const SStrMatch* pforms ); };
При поиске в словаре по шаблону для каждой лексемы, с формами которой обнаружено совпадение,
анализатор вызывает предоставленный пользователем метод AddLexeme. Это callback,
оформленный в виде активного интерфейса со средствами контроля времени жизни. Начиная взаимодействие
с ним, анализатор вызывает метод Attach(), а завершив – Detach(),
что позволяет использовать интерфейс асинхронно.
Addlexeme( ... ) получает уникальный идентификатор лексемы nlexid,
количество форм этой лексемы nforms, с которыми произошло отождествление шаблона, и массив
структур SStrMatch, описывающих каждое из совпадений строкой словоформы (mb или wc) её длиной
и идентификатором формы слова.
IMlmaMb и IMlmaWc
struct IMlma[Mb|Wc]
{
int Attach();
int Detach();
int CheckWord( ... );
int Lemmatize( ... );
int BuildForm( ... );
int FindForms( ... );
int GetWdInfo( ... );
int FindMatch( ... );
};Два похожих интерфейса с одинаковым набором функций, отличающиеся лишь типом строковых параметров: первый работает с multibyte-строками (const char*), второй – с UTF-16 (const widechar*)
Функции
Проверка правописания
int CheckWord( pszstr, cchstr, dwsets );
Функция выполняет проверку правописания слова по словарю и возвращает
- 1, если слово опознано;
- 0, если слово не опознано;
- значение меньше нуля в случае ошибки (коды ошибок см. выше).
Аргументы:
pszstr- указатель на строку, которую требуется проанализировать;cchstr- длина строки в символах или (unsigned)-1, если строка заканчивается нулевым символом;dwsets- настройки морфологического анализатора (см. выше).
Лемматизация
int Lemmatize( pszstr, cchstr, plexid, clexid, plemma, clemma, pgrams, ngrams, dwsets );
Функция выполняет отождествление поданной строки по морфологическому словарю и возвращает
- количество лексем, с формами которых произошло отождествление;
- 0, если слово не опознано;
- значение меньше нуля в случае ошибки (см. коды ошибок).
Аргументы:
pszstr- указатель на строку, которую требуется проанализировать;cchstr- длина строки в символах или (unsigned)-1, если строка заканчивается нулевым символом;plexid- указатель на массив для структурSLemmInfo;clexid- размерность этого массива;plemma- указатель на массив для словарных формы слов или NULL, если не требуется;clemma- размерность этого массива;pgrams- указатель на массив для грамматических описаний отождествлений или NULL, если не требуются;cgrams- размерность этого массива;dwsets- настройки морфологического анализатора.
Построение формы слова
int BuildForm( output, cchout, nlexid, idform );
Функция выполняет построение указанной формы слова для заданной лексемы, восстанавливает графические варианты начертания этой формы в выходной массив, разделяя их нулевым символом, и возвращает
- количество построенных вариантов начертания формы слова;
- 0, если слово не опознано;
- значение меньше нуля в случае ошибки (коды ошибок см. выше).
Аргументы:
output- указатель на массив для построенных вариантов формы слова;cchout- размерность этого массива;nlexid- идентификатор лексемы;idform- идентификатор формы слова.
Построение форм возможных лексем
int FindForms( output, cchout, pszstr, cchstr, idform );
Функция выполняет построение указанной формы слова для всех лексем, с которыми произойдет отождествление поданной словоформы. Данная функция полезна для использования в системах, которые не сохраняют идентификаторы лексем. Восстанавливает графические варианты начертания формы в выходной массив, разделяя их нулевым символом, и возвращает:
- количество построенных вариантов начертания формы слова;
- 0, если слово не опознано;
- значение меньше нуля в случае ошибки (коды ошибок см. выше).
Аргументы:
output- указатель на массив для построенных вариантов форм слов;cchout- размерность этого массива;pszstr- указатель на строку ключевой словоформы;cchstr- длина строки или (unsigned)-1, если строка заканчивается нулевым символом;idform- идентификатор формы слова.
Информация о лексеме
int GetWdInfo( pwinfo, nlexid );
Функция извлекает техническую часть речи для переданной лексемы и восстанавливает в переменную, на которую указывает первый параметр. Возвращает:
- 1 при успехе;
- 0, если такой лексемы не существует;
- значение меньше нуля в случае ошибки (см. коды ошибок).
Аргументы:
pwinfo- указатель на переменную для получения технической части речи;nlexid- идентификатор лексемы.
Поиск по шаблону
int FindMatch( pienum, pszstr, cchstr );
Функция выполняет поиск всех возможных форм всех словарных лексем, которые соответствуют переданному шаблону.
Шаблон может содержать буквы и символы * и ?. * соответствует любому количеству любых символов,
? – одному символу. Найденные лексемы и формы подаются по одной лексеме в переданный интерфейс
IFormsMatch. Вызовы продолжаются до тех пор, пока не будет завершён проход по словарю и пока
функция регистрации pienum->AddLexeme( ... ) не вернёт 0. Возвращает:
- 1 при успехе;
- значение меньше нуля в случае ошибки (см. коды ошибок).
Аргументы:
pmatch- указатель на интерфейсIFormsMatch;pszstr- указатель на строку ключевой словоформы;cchstr- длина строки или (unsigned)-1, если строка заканчивается нулевым символом.
CXX-расширение
Для удобства есть ещё синтаксический "сахарок" – интерфейсы IMlmaMbXX и IMlmaWcXX
с теми же функциями, но меньшим количеством аргументов:
struct IMlmaXX: Mlma { ... auto GetWdInfo( lexeme_t ) -> uint8_t; int CheckWord( inword[, dwsets] ); int Lemmatize( inword, lxbuff[, stbuff[, grbuff[, dwsets]]] ); auto Lemmatize( inword[, dwsets] ) -> std::vector; int BuildForm( outbuf, nlexid, formid_t ); auto BuildForm( nlexid, formid_t ) -> std::vector ; int FindForms( outbuf, inword, formid_t[, dwsets] ); auto FindForms( inword, formid_t[, dwsets] ) -> std::vector ; int FindMatch( IMlmaMatch*, inword ); int FindMatch( inword, FMatch ); };