Полнофункциональный порт phpMorphy на Node.JS.
Ниже представлена оригинальная документация к phpMorphy, с поправкой на javascript-синтаксис и реализованные возможности.
Последнюю версию библиотеки и исходный код можно взять с гитхаба.
Возможности
Библиотека позволяет решать следующие задачи:
- Лемматизация (получение нормальной формы слова);
- Получение всех форм слова;
- Получение грамматической информации для слова (часть речи, падеж, спряжение и т.д.);
- Изменение формы слова в соответствии с заданными грамматическими характеристиками;
- Изменение формы слова по заданному образцу.
Требования
Для работы библиотеки необходимы node@6 или выше, npm@3 или выше.
Установка
С помощью npm
npm install phpmorphy
С помощью yarn
yarn add phpmorphy
Подключение
ES2015:
;
CommonJS:
const Morphy = ;
Использование
Весь код библиотеки работает синхронно. Асинхронных аналогов методов нет и не будет, потому что:
- при установке опции
storage
в значениеMorphy.STORAGE_MEM
асинхронная работа просто не нужна - словари синхронно загружаются с диска в память единожды - при вызовеnew Morphy(...)
. Это означает, что создавать экземпляры Morpher'а для всех необходимых словарей лучше при старте приложения. Вся дальнейшая работа внутри библиотеки будет происходить без каких-либо задержек (словно вы работаете с обычными переменными или массивами). - Асинхронность нужна только при установке опции
storage
в значениеMorphy.STORAGE_FILE
, потому что в этом режиме при вызове любого метода происходит чтение с диска, что помедленней. Вся работа с файловой системой внутри библиотеки происходит синхронно. Для работы с ФС асинхронными методами пришлось бы переписывать большую часть логики кода phpMorphy.
Просто используйте Morphy.STORAGE_MEM
и не инициализируйте библиотеку в циклах.
Синхронный код также означает, что все брошенные библиотекой исключения вы можете спокойной ловить try/catch
ем.
Инициализация
const morphy = 'ru' // nojo: false, storage: MorphySTORAGE_MEM predict_by_suffix: true predict_by_db: true graminfo_as_text: true use_ancodes_cache: false resolve_ancodes: MorphyRESOLVE_ANCODES_AS_TEXT;
Поддерживаемые языки:
- на основе
AOT
словарей:- Русский (
ru
илиru_ru
); - Английский (
en
илиen_en
); - Немецкий (
de
илиde_de
);
- Русский (
- на основе
myspell
словарей:- Украинский (
ua
илиuk_ua
); - Эстонский (
ee
илиet_ee
).
- Украинский (
В myspell
словарях отсутствует грамматическая информация, потому часть функций для этих языков будет недоступна.
Опции
@property {Boolean} [nojo=false]
Используется только при инициализации русского языка. При установке значения в true
, будет подключён словарь, в котором все буквы ё
заменены на е
.
@todo: ещё не поддерживается. используются словари с буквой ё
@property {String} [storage=Morphy.STORAGE_MEM]
Morphy.STORAGE_FILE
- используются файловые операции. Потребляется небольшое количество памяти. Это самый медленный способ - на каждую операцию производится чтение с диска.Morphy.STORAGE_MEM
- словарь загружается в память при инициализации. Это самый быстрый способ доступа, но при этом словарь загружается для каждого экземпляра класса phpMorphy, что приводит к медленной инициализации библиотеки и большему потреблению памяти. В этом режиме логично инициализировать все необходимые экземпляры библиотеки при старте приложения.
@property {Boolean} [predict_by_suffix=true]
Использовать предсказание путем отсечения префикса. Для распознавания слов, образованных от известных путём прибавления префиксов ('популярный' => 'мегапопулярный' и т.п.).
@property {Boolean} [predict_by_db=true]
Использовать предсказание по окончанию.
@property {Boolean} [use_ancodes_cache=false]
Позволяет ускорить процесс получения грамматической информации (увеличивает потребление памяти во время исполнения и замедляет процесс инициализации).
Обратите внимание! Кэш анкодов доступен только для русского языка.
@property {Number} [resolve_ancodes=Morphy.RESOLVE_ANCODES_AS_TEXT]
Устанавливает способ преобразования анкодов.
Morphy.RESOLVE_ANCODES_AS_INT
- Используются числовые идентификаторы анкодов;Morphy.RESOLVE_ANCODES_AS_TEXT
- Развертывать анкод в текстовое представление. Формат - ЧАСТЬ_РЕЧИ граммема1, граммема2, и т.д.Morphy.RESOLVE_ANCODES_AS_DIALING
- Анкоды преобразуются к виду используемому в словарях AOT. (двухбуквенное обозначение). Доступно только для русского языка (если кто сможет собрать под остальные словари - велкам).
Методы
Сервисные
/** @returns */morphy;// 'utf-8'
Возвращает кодировку загруженного словаря. windows-1250
для английского или utf-8
для всех остальных словарей.
/** @returns */morphy;
Возвращает код языка. В формате: <код страны в ISO3166>_<код языка в ISO639>
.
ru_RU
, en_EN
, или uk_UA
и т.д., в зависимости от словаря.
/** @returns */morphy;
Возвращает экземпляр класса реализующий Morphy_Morphier_Interface
интерфейс. Используется только поиск по словарю.
/** @returns */morphy;
Возвращает экземпляр класса реализующий Morphy_Morphier_Interface
интерфейс. Используется только предсказание путем отсечения префикса.
/** @returns */morphy;
Возвращает экземпляр класса реализующий Morphy_Morphier_Interface
интерфейс. Используется только предсказание по окончанию.
/** @returns */morphy;
Возвращает экземпляр Morphy_Morphier_Bulk
класса. Используется пакетный режим обработки слов, только поиск по словарю.
Основные
/** @returns */morphy;
Функция не работает для bulk режима.
Возвращает true
если при анализе последнего слова выяснилось, что слово отсутствует в словаре и было предсказано. false
в ином случае.
const inspect = ;const log = console; // слова ГЛОКАЯ нет в словаре, слово ТЕСТ есть в словаре;// 'ГЛОКАЯ';// TRUE (слово было предсказано) ;// FALSE// если предыдущий вызов вернул FALSE, то isLastPredicted() возвращает FALSE;// FALSE morphy;;// FALSE (слово ТЕСТ было найдено в словаре) morphy;;// TRUE (был использован режим ONLY_PREDICT соответственно ТЕСТ было предсказано)
/** @returns */morphy;
Возвращает константу определяющую, каким способом было предсказано последнее слово. Функция не работает для bulk режима.
Morphy.PREDICT_BY_NONE
:- слово было найдено в словаре, предсказание не использовалось;
- либо слово отсутствует в словаре и предсказать его не удалось (к примеру, метод
morphy.lemmatize(word)
возвратилFALSE
);
Morphy.PREDICT_BY_SUFFIX
– слово было предсказано по окончанию;Morphy.PREDICT_BY_DB
– слово было предсказано по базе окончаний.
const inspect = ;const log = console; morphy;// слово ТЕСТ есть в словаре, предсказание не использовалось.;// TRUE morphy;// слово ГЛОКАЯ отсутствует в словаре, предсказать не удалось (lemmatize вернул FALSE).;// TRUE morphy;;// TRUE morphy;;// TRUE
Следующие методы имеют схожую сигнатуру.
/** * @param * @param * @returns */morphy;morphy;morphy;morphy;morphy;morphy;// и т.д.
Первый параметр word
может быть:
- строкой. Это слово для анализа. Если слово не было найдено в словаре или предсказано, функция возвращает
FALSE
. - массивом слов для анализа. Это так называемый
bulk
-режим. Благодаря некоторым оптимизациям внутри кода, позволяет увеличить скорость обработки слов на ~50%. В данном режиме функция возвращает массив, в качестве ключа выступает исходное слово, соответствующее значение – результат.
const inspect = ;const log = console; const words = 'СОБАКА' 'КОШКА';const result = {}; words; ;// { 'СОБАКА': [ 'СОБАКА' ], 'КОШКА': [ 'КОШКА' ] }
result
можно получить на 50% быстрее в bulk
-режиме:
const inspect = ;const log = console; const words = 'СОБАКА' 'КОШКА';const result = morphy;;// { 'СОБАКА': [ 'СОБАКА' ], 'КОШКА': [ 'КОШКА' ] }
Следует заметить, что morphy.getLastPredictionType()
и morphy.isLastPredicted()
не работают в bulk
-режиме.
Второй параметр type
– указывает порядок обработки для конкретного слова (списка слов в bulk
-режиме). Может принимать значения:
Morphy.NORMAL
– значение по умолчанию. В этом режиме обработка слова производится в следующем порядке:- идет поиск в словаре;
- если в словаре слово не найдено, то пытаемся предсказать в соответствии с настройками предсказания при инициализации (опции
predict_by_suffix
иpredict_by_db
); - если предсказать не удалось, возвращаем FALSE.
Morphy.IGNORE_PREDICT
– отключает предсказание. Т.е. поиск слова идет только по словарю. Если слова в словаре нет, возвращает FALSEMorphy.ONLY_PREDICT
– отключает поиск по словарю. Используется только предсказание, в соответствии с настройками предсказания при инициализации. Если предсказать не удалось (к примеру,predict_by_suffix
иpredict_by_db
установлены в false) возвращаем FALSE.
Далее будут описаны только уникальные свойства для каждого метода, на основе одиночного режима (для bulk
-режима результат помещается в массив).
/** * @param * @param * @returns */morphy;
Производит анализ слова, возвращает коллекцию типа Morphy_WordDescriptor_Collection
.
Используется для детального анализа слов.
const inspect = ;const log = console; const word = 'ДУША';const paradigms = morphy; if !paradigms throw 'Can`t find word'; // paradigms instanceof Morphy_WordDescriptor_Collection // получить только существительные можно при помощиparadigms; // обрабатываем омонимыparadigms;
/** * @param * @param * @returns */morphy;
Возвращает лемму (базовую форму) слова. Из-за присутствия омонимии, результат возвращается в виде массива. Т.е. метод возвращает леммы для всех слов, из которых может быть образована искомая словоформа.
const inspect = ;const log = console; ; // [ 'КОЛБАСА' ]; // [ 'ТЕСТ', 'ТЕСТО' ] // ТЕСТ отождествляется с формами слов// ТЕСТ – единственное число, именительный, винительный падежи// ТЕСТО – множественное число, родительный падеж; // FALSE ;// {// 'ТЕСТ': [ 'ТЕСТ', 'ТЕСТО' ],// 'КОЛБАСЫ': [ 'КОЛБАСА' ],// 'ГЛОКАЯ': false// }
/** * @param * @param * @returns */morphy;
Это синоним для метода lemmatize
.
/** * @param * @param * @returns */morphy;
Возвращает список всех форм (в виде массива) для слова. Если word отождествляется с формами разных слов, словоформы для каждого слова сливаются в один массив.
const inspect = ;const log = console; ;// все формы для слов ТЕСТ и ТЕСТО:// [ 'ТЕСТ', 'ТЕСТА', 'ТЕСТУ', 'ТЕСТОМ', 'ТЕСТЕ', 'ТЕСТЫ', 'ТЕСТОВ', 'ТЕСТАМ', 'ТЕСТАМИ', 'ТЕСТАХ', 'ТЕСТО' ]
/** * @param * @param * @returns */morphy;
Возвращает общую часть для всех словоформ заданного слова. Общая часть может быть пустой (к примеру, для слова ДЕТИ). Этот метод не возвращает корень слова в привычном его понимании (только longest common substring для всех словоформ). Всегда возвращает строку (не массив!).
const inspect = ;const log = console; ; // [ 'ТЕСТ' ]; // [ '' ]
/** * @param * @param * @returns */morphy;
Возвращает часть речи для заданного слова. Т.к. словоформа может образовываться от нескольких слов, метод возвращает массив. Возвращаемое значение зависит от опции инициализации graminfo_as_text
. Если graminfo_as_text == true
часть речи представляется в текстовом виде, иначе в виде значения константы (эта возможность отключена).
const inspect = ;const log = console; // ТЕСТ образовывается от ТЕСТ и ТЕСТО, однако оба слова являются существительными; // [ 'С' ] // ДУША образовывается от ДУШ, ДУША и ДУШИТЬ; // [ 'С', 'ДЕЕПРИЧАСТИЕ' ]
/** * @param * @param * @param * @returns */morphy;
Данный метод рекомендуется использовать только для отладки. Для анализа используйте метод findWord()
.
Если asText == true
грамматическая информация возвращается в виде строки, иначе в виде массива:
const inspect = ;const log = console; ;/*[ // омоним №1 { all: [ // массив содержит часть речи и граммемы для каждой // формы из 'forms'. Граммемы разделены запятой. // Часть речи отделена от граммем пробелом. 'С ЕД,ИМ,МР,НО', 'С ВН,ЕД,МР,НО', 'С ЕД,МР,НО,РД', 'С ДТ,ЕД,МР,НО', 'С ЕД,МР,НО,ТВ', 'С ЕД,МР,НО,ПР', 'С ИМ,МН,МР,НО', 'С ВН,МН,МР,НО', 'С МН,МР,НО,РД', 'С ДТ,МН,МР,НО', 'С МН,МР,НО,ТВ', 'С МН,МР,НО,ПР' ], forms: [ 'ТЕСТ', 'ТЕСТ', 'ТЕСТА', 'ТЕСТУ', 'ТЕСТОМ', 'ТЕСТЕ', 'ТЕСТЫ', 'ТЕСТЫ', 'ТЕСТОВ', 'ТЕСТАМ', 'ТЕСТАМИ', 'ТЕСТАХ' ], common: '' }, // омоним №2 { all: [ 'С ЕД,ИМ,НО,СР', 'С ВН,ЕД,НО,СР', 'С ЕД,НО,РД,СР', 'С ИМ,МН,НО,СР', 'С ВН,МН,НО,СР', 'С ДТ,ЕД,НО,СР', 'С ЕД,НО,СР,ТВ', 'С ЕД,НО,ПР,СР', 'С МН,НО,РД,СР', 'С ДТ,МН,НО,СР', 'С МН,НО,СР,ТВ', 'С МН,НО,ПР,СР' ], forms: [ 'ТЕСТО', 'ТЕСТО', 'ТЕСТА', 'ТЕСТА', 'ТЕСТА', 'ТЕСТУ', 'ТЕСТОМ', 'ТЕСТЕ', 'ТЕСТ', 'ТЕСТАМ', 'ТЕСТАМИ', 'ТЕСТАХ' ], common: '' }]*/ ;/*[ // омоним №1 { all: [ {pos: 'С', grammems: ['ЕД', 'ИМ', 'МР', 'НО']}, {pos: 'С', grammems: ['ВН', 'ЕД', 'МР', 'НО']}, {pos: 'С', grammems: ['ЕД', 'МР', 'НО', 'РД']}, {pos: 'С', grammems: ['ДТ', 'ЕД', 'МР', 'НО']}, {pos: 'С', grammems: ['ЕД', 'МР', 'НО', 'ТВ']}, {pos: 'С', grammems: ['ЕД', 'МР', 'НО', 'ПР']}, {pos: 'С', grammems: ['ИМ', 'МН', 'МР', 'НО']}, {pos: 'С', grammems: ['ВН', 'МН', 'МР', 'НО']}, {pos: 'С', grammems: ['МН', 'МР', 'НО', 'РД']}, {pos: 'С', grammems: ['ДТ', 'МН', 'МР', 'НО']}, {pos: 'С', grammems: ['МН', 'МР', 'НО', 'ТВ']}, {pos: 'С', grammems: ['МН', 'МР', 'НО', 'ПР']} ], forms: [ 'ТЕСТ', 'ТЕСТ', 'ТЕСТА', 'ТЕСТУ', 'ТЕСТОМ', 'ТЕСТЕ', 'ТЕСТЫ', 'ТЕСТЫ', 'ТЕСТОВ', 'ТЕСТАМ', 'ТЕСТАМИ', 'ТЕСТАХ' ], common: '' }, // омоним №2 { all: [ {pos: 'С', grammems: ['ЕД', 'ИМ', 'НО', 'СР']}, {pos: 'С', grammems: ['ВН', 'ЕД', 'НО', 'СР']}, {pos: 'С', grammems: ['ЕД', 'НО', 'РД', 'СР']}, {pos: 'С', grammems: ['ИМ', 'МН', 'НО', 'СР']}, {pos: 'С', grammems: ['ВН', 'МН', 'НО', 'СР']}, {pos: 'С', grammems: ['ДТ', 'ЕД', 'НО', 'СР']}, {pos: 'С', grammems: ['ЕД', 'НО', 'СР', 'ТВ']}, {pos: 'С', grammems: ['ЕД', 'НО', 'ПР', 'СР']}, {pos: 'С', grammems: ['МН', 'НО', 'РД', 'СР']}, {pos: 'С', grammems: ['ДТ', 'МН', 'НО', 'СР']}, {pos: 'С', grammems: ['МН', 'НО', 'СР', 'ТВ']}, {pos: 'С', grammems: ['МН', 'НО', 'ПР', 'СР']} ], forms: [ 'ТЕСТО', 'ТЕСТО', 'ТЕСТА', 'ТЕСТА', 'ТЕСТА', 'ТЕСТУ', 'ТЕСТОМ', 'ТЕСТЕ', 'ТЕСТ', 'ТЕСТАМ', 'ТЕСТАМИ', 'ТЕСТАХ' ], common: '' }]*/
/** * @param * @param * @returns */morphy;
Вывод похож на getAllFormsWithGramInfo()
, но грамматическая информация возвращается в виде анкодов (согласно опции resolve_ancodes
). Если resolve_ancodes == Morphy.RESOLVE_ANCODES_AS_TEXT
(по умолчанию), то вывод аналогичен morphy.getAllFormsWithGramInfo(word, true)
.
const inspect = ;const log = console; let morphy; morphy = 'ru' resolve_ancodes: MorphyRESOLVE_ANCODES_AS_TEXT // <==; ;/*[ { all: [ 'МС 1Л,ЕД,ИМ', 'МС 1Л,ЕД,РД', 'МС 1Л,ЕД,ВН', 'МС 1Л,ЕД,ДТ', 'МС 1Л,ЕД,ПР', 'МС 1Л,ЕД,ТВ', 'МС 1Л,ЕД,ТВ' ], forms: ['Я', 'МЕНЯ', 'МЕНЯ', 'МНЕ', 'МНЕ', 'МНОЙ', 'МНОЮ'], common: null }]*/ morphy = 'ru' resolve_ancodes: MorphyRESOLVE_ANCODES_AS_INT // <==; ;/*[ { all: [471, 472, 474, 473, 476, 475, 475], forms: ['Я', 'МЕНЯ', 'МЕНЯ', 'МНЕ', 'МНЕ', 'МНОЙ', 'МНОЮ'], common: null }]*/ morphy = 'ru' resolve_ancodes: MorphyRESOLVE_ANCODES_AS_DIALING // <==; ;/*[ { all: ['ча', 'чб', 'чг', 'чв', 'че', 'чд', 'чд'], forms: ['Я', 'МЕНЯ', 'МЕНЯ', 'МНЕ', 'МНЕ', 'МНОЙ', 'МНОЮ'], common: null }]*/
/** * @param * @param * @returns */morphy;
Возвращает анкоды для слова.
const inspect = ;const log = console; let morphy; morphy = 'ru' resolve_ancodes: MorphyRESOLVE_ANCODES_AS_TEXT // <==; ;/*[ {common: ' НО', all: ['С МР,ЕД,ИМ', 'С МР,ЕД,ВН']}, {common: ' НО', all: ['С СР,МН,РД']}]*/ morphy = 'ru' resolve_ancodes: MorphyRESOLVE_ANCODES_AS_INT // <==; ;/*[ {common: 687, all: [0, 4]}, {common: 687, all: [115]}]*/ morphy = 'ru' resolve_ancodes: MorphyRESOLVE_ANCODES_AS_DIALING // <==; ;/*[ {common: 'Фа', all: ['аа', 'аг']}, {common: 'Фа', all: ['ез']}]*/
/** * @param * @param * @returns */morphy;
Возвращает грамматическую информацию для слова
const inspect = ;const log = console; ;/*[ [ {pos: 'С', grammems: ['ВН', 'ЕД', 'МР', 'НО'], form_no: 0}, {pos: 'С', grammems: ['ЕД', 'ИМ', 'МР', 'НО'], form_no: 0} ], [{pos: 'С', grammems: ['МН', 'НО', 'РД', 'СР'], form_no: 5}]]*/
/** * @param * @param * @returns */morphy;
Вывод аналогичен getGramInfo, но если внутри одной парадигмы найдено несколько слов, граммемы сливаются в один массив.
const inspect = ;const log = console; ; /*[ { pos: 'С', grammems: ['ВН', 'ЕД', 'ИМ', 'МР', 'НО'], forms_count: 2, form_no_low: 0, form_no_high: 2 }, { pos: 'С', grammems: ['МН', 'НО', 'РД', 'СР'], forms_count: 1, form_no_low: 5, form_no_high: 6 }]*/
Обратите внимание, граммемы ИМ
и ВН
для парадигмы слова ТЕСТ
(не ТЕСТО
) объединены в один массив, в отличие от getGramInfo()
.
/** * @param * @param * @param * @param * @param * @param * @return {[]|boolean} */morphy;
Приводит слово в заданную форму. partOfSpeech – необходим только для прилагательных и глаголов т.к. только для этих частей речи внутри парадигмы встречаются различные части речи. Если partOfSpeech == null, часть речи не используется.
const inspect = ;const log = console; const word = 'ШКАФ'; // поставим слово ШКАФ в множественное число, предложный падеж;/*[ { form: 'ШКАФАХ', form_no: 12, pos: 'С', grammems: ['МР', 'МН', 'ПР', 'НО'] }]*/ // возвращает только слово, без грамматической информации;// [ 'ШКАФАХ' ] // применим пользовательский фильтр// фильтр – предикат (функция возвращающая true/false) со следующей сигнатурой:// function XXX(form, partOfSpeech, grammems, formNo)// если функция возвращает TRUE, то исходное слово приводится в данную форму// callback – обычная функция обратного вызова { return grammems;} // приведём ШКАФ в именительный падеж;// [ 'ШКАФ', 'ШКАФЫ' ] // выберем краткое прилагательное единственного числа, женского рода.// если не указать часть речи, будут выбраны все прилагательные единственного числа, женского рода;// [ 'КРАСНА' ]
/** * @param * @param * @param * @param * @param * @param * @return {[]|boolean} */morphy;
Приводит слово word в форму, в которой стоит слово patternWord.
const inspect = ;const log = console; ;// [ 'ДИВАНАМИ' ]
Сложность возникает, если некоторые граммемы у слов не совпадают. Т.к. данная функция ищет в парадигме слова word
форму, у которой граммемы совпадают с граммемами patternWord
, то в таких случаях на выходе получим пустой результат. Например, ДИВАН
и КРОВАТЬ
имеют разный род (мужской и женский соответственно).
const inspect = ;const log = console; ;// []
Нам требуется указать, что род сравнивать не нужно. Можно это сделать следующим способом:
const inspect = ;const log = console; const provider = morphy;provider;/*указываем, что для существительных род сравнивать не будем. Первым параметром указывается часть речи, для которой требуется внести измененияВторым - группу граммем, которую необходимо исключить, может принимать следующие значения:1) род2) одушевленность 3) число 4) падеж 5) залог 6) время 7) повелительная форма 8) лицо9) сравнительная форма 10) превосходная степень11) вид12) переходность13) безличный глагол следует помнить, что все данные должны быть в кодировке словаря*/;// [ 'ДИВАНАМИ' ];// [ 'КРЕСЛАМИ' ] // Чтобы не передавать provider каждый раз, можно сделать изменения глобальноmorphy;;// [ 'ДИВАНАМИ' ]
/** * @param * @param * @param * @param * @param * @param * @return */morphy;
Аналогично castFormByGramInfo
, но грамматическая информация указывается в виде анкода (согласно опции resolve_ancodes
).