В практике разработки на платформе 1С часто возникает задача нормализации текста. Типичный пример: на вход поступает фраза или отдельное слово в косвенном падеже (например, «кошке»), а системе необходимо получить его исходную форму («кошка») или склонения во всех остальных падежах. Эта задача в лингвистике называется лемматизацией.
Проблема заключается в том, что стандартные средства платформы и даже многие внешние сервисы хорошо работают в «прямом» направлении (из именительного падежа в остальные), но пасуют перед задачей «разворота» слова. Рассмотрим подробнее, почему это происходит, и разберем по шагам эффективные методы решения этой проблемы.
Проанализируем ситуацию с точки зрения лингвистики. Основная сложность заключается в явлении, которое называется морфологической омонимией. Одно и то же слово в косвенном падеже может соответствовать нескольким разным словам в именительном падеже.
Рассмотрим классические примеры, иллюстрирующие эту неоднозначность:
Именно поэтому универсальное алгоритмическое решение, основанное только на правилах окончаний, часто выдает ошибки. Однако в рамках бизнес-логики 1С мы можем применить комплексный подход, который минимизирует вероятность ошибки.
Прежде всего, проверим возможности платформы. В 1С существуют методы ПолучитьСклоненияСтрокиПоЧислу и ПолучитьСклоненияСтроки. Хотя они предназначены для прямого склонения, иногда их можно использовать для верификации гипотез.
Если мы предполагаем, что исходное слово — «кошка», мы можем просклонять его и сравнить результат с имеющимся у нас словом «кошке». Если формы совпали, значит, лемма найдена верно. Выглядит это примерно так:
РезультатСклонения = СклонениеПредставленийОбъектов.ПросклонятьПредставление("Кошка", 3); // 3 - Дательный падеж
Если РезультатСклонения = "кошке" Тогда
// Гипотеза подтверждена
КонецЕсли;
Однако этот метод требует знания исходного слова, что возвращает нас к исходной проблеме. Поэтому перейдем к более сложным инструментам.
Самый надежный способ для работы с ограниченным или часто используемым набором слов — создание внутреннего справочника в базе 1С. Разберем структуру такого решения:
СловарныйЗапас.Падежи с реквизитами для каждого падежа (Именительный, Родительный, Дательный и т.д.).При поиске мы используем простой запрос. Выясним причину эффективности этого метода: поиск по проиндексированным полям табличной части работает мгновенно даже на больших объемах данных.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| СловарныйЗапас.Ссылка КАК Лемма
|ИЗ
| Справочник.СловарныйЗапас.Падежи КАК Падежи
|ГДЕ
| Падежи.Словоформа = &ИскомоеСлово";
Запрос.УстановитьПараметр("ИскомоеСлово", "кошке");
Результат = Запрос.Выполнить();
Если слова нет в справочнике, можно применить дерево условий по окончаниям. Посмотрим на пример логики для существительных первого склонения. Если слово заканчивается на «е» и мы знаем, что это дательный падеж, мы можем предположить, что в именительном падеже оно должно оканчиваться на «а» или «я».
Внимание: этот метод крайне неточен для слов типа «Ване» (Ваня) против «ванне» (ванна). Поэтому его следует использовать только как вспомогательный.
Для достижения максимальной точности (около 90–95%) следует использовать специализированные лингвистические инструменты. Рассмотрим наиболее эффективные:
ЗапуститьПриложение. Она уникальна тем, что умеет учитывать контекст предложения, решая проблему «вино/вина».Наилучшим вариантом, к которому приходят опытные разработчики, является «сборка» из четырех этапов. Проанализируем алгоритм, который позволяет эффективно разбирать семантическое ядро:
Шаг 1: Правила окончаний.
Программа пытается применить простые трансформации окончаний для получения списка кандидатов.
Шаг 2: Внутренний справочник.
Проверяем наличие слова в нашей базе данных. Если слово «кошке» уже встречалось ранее, мы мгновенно получаем «кошка».
Шаг 3: Встроенное склонение 1С.
Используем ПолучитьСклоненияСтроки для проверки наиболее вероятных кандидатов, полученных на Шаге 1.
Шаг 4: Внешний запрос.
Если внутренние средства не дали однозначного ответа, обращаемся к API (например, Morpher или сервис на базе OpenCorpora).
Рассмотрим пример того, как собрать массив всех возможных форм, имея на входе только слово в дательном падеже:
Функция ПолучитьВсеПадежиИзКосвенного(СловоВПадеже)
МассивРезультатов = Новый Массив;
// 1. Пытаемся найти в справочнике
Лемма = НайтиВЛокальномСловаре(СловоВПадеже);
Если ЗначениеЗаполнено(Лемма) Тогда
МассивРезультатов = ПолучитьВсеСклонения(Лемма);
Возврат МассивРезультатов;
КонецЕсли;
// 2. Если не нашли, запрашиваем внешний сервис
Лемма = ПолучитьЛеммуЧерезAPI(СловоВПадеже);
// 3. Получив лемму, генерируем все формы через 1С
Если ЗначениеЗаполнено(Лемма) Тогда
// Используем стандартную функцию платформы для получения массива
МассивРезультатов = ПолучитьСклоненияСтроки(Лемма);
КонецЕсли;
Возврат МассивРезультатов;
КонецФункции
Такой подход позволяет автоматизировать обработку текстов на 90%. Оставшиеся 10% сложных случаев (омонимов) обычно корректируются вручную или через анализ контекста (соседних слов). Использование готовых открытых корпусов, таких как OpenCorpora, позволяет загрузить в 1С сотни тысяч выверенных словоформ, что превращает «нерешаемую» задачу в обычную операцию поиска по базе данных.