Задача склонения Фамилии, Имени и Отчества (ФИО) — одна из самых распространенных в практике программирования на 1С. Она возникает при формировании печатных форм договоров, доверенностей, приказов и других документов, где требуется указать, от кого или кому выдан документ.
В данной статье мы подробно разберем, как решить эту задачу. Мы рассмотрим два основных подхода:
Начиная с версии платформы 8.3.13, разработчики 1С внедрили нативный механизм склонения. Это означает, что вам больше не нужно писать сложные алгоритмы или подключать внешние компоненты типа NameDecl.dll. Весь функционал уже находится "под капотом".
Для склонения используется глобальная функция ПолучитьСклоненияСтроки. Давайте разберем её синтаксис и особенности применения.
Функция принимает на вход следующие параметры:
Рассмотрим пример кода, который получает ФИО в родительном падеже (кого? чего?).
// Пример склонения ФИО в родительный падеж
ФИО = "Иванов Иван Иванович";
ПараметрыСклонения = "ПЛ=Мужской;ПД=Родительный"; // Указываем пол и падеж
// Функция возвращает Массив строк
РезультатСклонения = ПолучитьСклоненияСтроки(ФИО, ПараметрыСклонения);
Если РезультатСклонения.Количество() > 0 Тогда
ФИО_Родительный = РезультатСклонения[0];
Сообщить("Результат: " + ФИО_Родительный); // Выведет: Иванова Ивана Ивановича
Иначе
Сообщить("Не удалось просклонять строку");
КонецЕсли;
Важные нюансы работы метода:
ПЛ (Пол) указывать необязательно, система умеет определять его автоматически. Однако, если вы точно знаете пол (например, берете его из карточки физлица), лучше его передать явно, чтобы избежать ошибок с несклоняемыми или двусмысленными фамилиями.ПД (Падеж) может принимать значения: Именительный, Родительный, Дательный, Винительный, Творительный, Предложный.Если вы работаете с более старой версией платформы или по каким-то причинам встроенный метод недоступен (например, отключена системная компонента склонения на сервере), необходимо использовать алгоритмический подход.
Ниже представлен код функции, которая разбирает строку ФИО (для сложного разбора могут пригодиться регулярные выражения), определяет окончания и меняет их в соответствии с правилами русского языка. Этот код полностью автономен и может быть вставлен в любой общий модуль или модуль объекта.
Данная функция (авторства Якова и Софьи Коган) хорошо структурирована и позволяет получить ФИО в нужном падеже.
Рассмотрим код функции подробно. Вы можете скопировать его к себе в конфигурацию.
// Функция возвращает фамилию, имя и отчество в нужном падеже
//
// Параметры:
// ФИО - Строка - Фамилия Имя Отчество одной строкой
// Падеж - Число - номер падежа (1-6) или строка (первая буква падежа)
// 2 - Родительный
// ТолькоИнициалы - Булево - если Истина, вернет "Фамилия И.О."
//
Функция ПадежФИО(Знач ФИО, Падеж = 2, ТолькоИнициалы = Ложь) Экспорт
// 1. Предварительная очистка и проверка входных данных
Если ТипЗнч(ФИО) <> Тип("Строка") Тогда
Возврат ФИО;
КонецЕсли;
ФИО = СокрЛП(ФИО);
// Если запрошен Именительный падеж - возвращаем исходную строку
Если (Лев(Падеж, 1) = "И") ИЛИ (Падеж = 1) Тогда
Возврат ФИО;
КонецЕсли;
// Определение номера падежа, если передана строка
Если ТипЗнч(Падеж) = Тип("Строка") Тогда
СтрокаПадежа = СокрЛП(НРег(Лев(Падеж, 1)));
Если Найти("рдвтп", СтрокаПадежа) = 0 Тогда
Возврат ФИО; // Неизвестный падеж
КонецЕсли;
// Маппинг букв в индексы колонок таблицы правил
// р-родительный, д-дательный и т.д. В коде ниже используются имена колонок
ИмяКолонкиПадежа = СтрокаПадежа;
ИначеЕсли ТипЗнч(Падеж) = Тип("Число") Тогда
Если Падеж < 2 ИЛИ Падеж > 6 Тогда
Возврат ФИО;
КонецЕсли;
// Преобразуем число в имя колонки таблицы правил
ИменаКолонок = "р,д,в,т,п"; // Соответствует падежам 2,3,4,5,6
МассивКолонок = СтрРазделить(ИменаКолонок, ",");
ИмяКолонкиПадежа = МассивКолонок[Падеж - 2];
КонецЕсли;
ФИО = НРег(ФИО); // Работаем в нижнем регистре
// Разбор строки на составляющие
СтрРазбора = СтрЗаменить(ФИО, " ", Символы.ПС);
Фамилия = СокрЛП(СтрПолучитьСтроку(СтрРазбора, 1));
Имя = СокрЛП(СтрПолучитьСтроку(СтрРазбора, 2));
Отчество = СокрЛП(СтрПолучитьСтроку(СтрРазбора, 3));
// Определение пола по отчеству
Если Прав(Отчество, 1) = "а" Тогда
Пол = "Ж";
Иначе
Пол = "М";
КонецЕсли;
// Создаем таблицу правил склонения
ТаблицаПравил = Новый ТаблицаЗначений;
ТаблицаПравил.Колонки.Добавить("СтарОк", Новый ОписаниеТипов("Строка")); // Старое окончание
ТаблицаПравил.Колонки.Добавить("р"); // Родительный
ТаблицаПравил.Колонки.Добавить("д"); // Дательный
ТаблицаПравил.Колонки.Добавить("в"); // Винительный
ТаблицаПравил.Колонки.Добавить("т"); // Творительный
ТаблицаПравил.Колонки.Добавить("п"); // Предложный
ТаблицаПравил.Колонки.Добавить("КолвоСрез", Новый ОписаниеТипов("Число")); // Сколько букв отрезать
Гласные = "аеэоуиыяюьъ";
// --- ОБРАБОТКА ФАМИЛИИ ---
НовФамилия = Фамилия;
// Исключение: фамилии на "х" (обычно не склоняются в простых алгоритмах, кроме -их/-ых)
Если Прав(Фамилия, 1) <> "х" Тогда
ТаблицаПравил.Очистить();
Если Пол = "М" Тогда
ДобавитьПравило(ТаблицаПравил, "*s", "а", "у", "а", "ым", "е", 0); // Иванов -> Иванова
ДобавитьПравило(ТаблицаПравил, "*й", "ого", "ому", "ого", "им", "ом", 2); // Красинский
ДобавитьПравило(ТаблицаПравил, "ый", "ого", "ому", "ого", "ым", "ом", 2); // Белый
ДобавитьПравило(ТаблицаПравил, "*й", "я", "ю", "я", "ем", "е", 1); // Палей -> Палея
ДобавитьПравило(ТаблицаПравил, "*ч", "а", "у", "а", "ем", "е", 0); // Рабинович
ДобавитьПравило(ТаблицаПравил, "*к", "ка", "ку", "ка", "ком", "ке", 2); // Зализняк -> Зализняка
ДобавитьПравило(ТаблицаПравил, "*ь", "я", "ю", "я", "ем", "е", 1); // Шинкарь
ДобавитьПравило(ТаблицаПравил, "*н", "а", "у", "а", "ом", "е", 0);
ДобавитьПравило(ТаблицаПравил, "ин", "а", "у", "а", "ым", "е", 0); // Баранкин
ИначеЕсли Пол = "Ж" Тогда
ДобавитьПравило(ТаблицаПравил, "ая", "ой", "ой", "ую", "ой", "ой", 2); // Склодовская
ДобавитьПравило(ТаблицаПравил, "*а", "ой", "ой", "у", "ой", "ой", 1); // Иванова
КонецЕсли;
НовФамилия = ПрименитьПравила(Фамилия, ТаблицаПравил, ИмяКолонкиПадежа, Гласные);
КонецЕсли;
// --- ОБРАБОТКА ИМЕНИ ---
ТаблицаПравил.Очистить();
НовИмя = Имя;
Если Пол = "М" Тогда
// Исключения имен
Если Имя = "лев" Тогда Имя = "льв"; КонецЕсли;
Если Имя = "павел" Тогда Имя = "павл"; КонецЕсли;
ДобавитьПравило(ТаблицаПравил, "*й", "я", "ю", "я", "ем", "е", 1); // Сергей
ДобавитьПравило(ТаблицаПравил, "*s", "а", "у", "а", "ом", "е", 0); // Иван
ДобавитьПравило(ТаблицаПравил, "*а", "ы", "е", "у", "ой", "е", 1); // Никита
ДобавитьПравило(ТаблицаПравил, "ка", "и", "е", "у", "ой", "е", 1); // Лука
ДобавитьПравило(ТаблицаПравил, "ия", "и", "и", "ю", "ей", "и", 1); // Иеремия
ДобавитьПравило(ТаблицаПравил, "*я", "и", "е", "ю", "ей", "е", 1); // Илья
ДобавитьПравило(ТаблицаПравил, "*ь", "я", "ю", "я", "ем", "е", 1); // Игорь
ИначеЕсли Пол = "Ж" Тогда
ДобавитьПравило(ТаблицаПравил, "*а", "ы", "е", "у", "ой", "е", 1); // Ирина
ДобавитьПравило(ТаблицаПравил, "га", "и", "е", "у", "ой", "е", 1); // Инга, Ольга
ДобавитьПравило(ТаблицаПравил, "*ь", "и", "и", "ь", "ью", "и", 1); // Любовь
ДобавитьПравило(ТаблицаПравил, "ия", "и", "и", "ю", "ей", "и", 1); // Мария
ДобавитьПравило(ТаблицаПравил, "*я", "и", "е", "ю", "ей", "е", 1); // Софья
КонецЕсли;
НовИмя = ПрименитьПравила(Имя, ТаблицаПравил, ИмяКолонкиПадежа, Гласные);
// --- ОБРАБОТКА ОТЧЕСТВА ---
ТаблицаПравил.Очистить();
НовОтчество = Отчество;
Если Пол = "М" Тогда
ДобавитьПравило(ТаблицаПравил, "", "а", "у", "а", "ем", "е", 0);
ИначеЕсли Пол = "Ж" Тогда
ДобавитьПравило(ТаблицаПравил, "", "ы", "е", "у", "ой", "е", 1);
КонецЕсли;
Если Не ПустаяСтрока(Отчество) И ТаблицаПравил.Количество() > 0 Тогда
Основа = Лев(Отчество, СтрДлина(Отчество) - ТаблицаПравил[0].КолвоСрез);
НовОтчество = Основа + СокрЛП(ТаблицаПравил[0][ИмяКолонкиПадежа]);
КонецЕсли;
// Формирование результата
Если ТолькоИнициалы Тогда
НовИмя = Лев(НовИмя, 1) + ".";
НовОтчество = Лев(НовОтчество, 1) + ".";
Иначе
// Восстанавливаем заглавные буквы
НовИмя = ВРег(Лев(НовИмя, 1)) + Сред(НовИмя, 2);
НовОтчество = ВРег(Лев(НовОтчество, 1)) + Сред(НовОтчество, 2);
КонецЕсли;
НовФамилия = ВРег(Лев(НовФамилия, 1)) + Сред(НовФамилия, 2);
Возврат СокрЛП(НовФамилия + " " + НовИмя + " " + НовОтчество);
КонецФункции
// Служебная процедура добавления правила (для компактности кода)
Процедура ДобавитьПравило(ТЗ, СтарОк, р, д, в, т, п, КолвоСрез)
НовСтр = ТЗ.Добавить();
НовСтр.СтарОк = СтарОк;
НовСтр.р = р; НовСтр.д = д; НовСтр.в = в; НовСтр.т = т; НовСтр.п = п;
НовСтр.КолвоСрез = КолвоСрез;
КонецПроцедуры
// Служебная функция поиска и применения правила
Функция ПрименитьПравила(Слово, ТЗ, ИмяКолонкиПадежа, Гласные)
Если ПустаяСтрока(Слово) Тогда Возврат ""; КонецЕсли;
ПБ = Прав(Слово, 2); // Последние две буквы
// 1. Ищем точное совпадение двух последних букв
СтрокаПравила = ТЗ.Найти(ПБ, "СтарОк");
// 2. Если не нашли, ищем по шаблону с одной последней буквой
Если СтрокаПравила = Неопределено Тогда
ПБ = "*" + Прав(ПБ, 1);
СтрокаПравила = ТЗ.Найти(ПБ, "СтарОк");
КонецЕсли;
// 3. Если не нашли, определяем тип последней буквы (гласная/согласная)
Если СтрокаПравила = Неопределено Тогда
ТипБуквы = ?(Найти(Гласные, Прав(Слово, 1)) = 0, "s", "g"); // s - согласная, g - гласная
ПБ = "*" + ТипБуквы;
СтрокаПравила = ТЗ.Найти(ПБ, "СтарОк");
КонецЕсли;
Если СтрокаПравила <> Неопределено Тогда
Основа = Лев(Слово, СтрДлина(Слово) - СтрокаПравила.КолвоСрез);
Возврат Основа + СокрЛП(СтрокаПравила[ИмяКолонкиПадежа]);
Иначе
Возврат Слово; // Если правило не найдено, возвращаем как есть
КонецЕсли;
КонецФункции
Алгоритмический метод, в отличие от нативного, не содержит встроенного словаря всех имен мира. Он работает по принципу анализа окончаний слов, что делает его компактным, но требующим внимания к исключениям.
Рассмотрим по шагам, что делает функция ПадежФИО:
*s). Нужно отрезать 0 букв и добавить "а" (для родительного падежа). Результат: Иванов + а = Иванова.Проанализируем плюсы и минусы обоих подходов:
Метод ПолучитьСклоненияСтроки (Платформа):
Алгоритмическая функция (Код 1С):
Для простых задач склонения (договоры, приказы) в современных конфигурациях настоятельно рекомендуем использовать первый вариант. Второй вариант следует применять только как резервный.