Как в 1С получить фамилию, имя и отчество физического лица в отдельных переменных?

Программист 1С v8.3 (Управляемые формы) 1С:Розница Торговля и дистрибуция
← На главную

При работе с данными физических лиц в 1С часто возникает задача получить не полное ФИО одной строкой, а его составные части — фамилию, имя и отчество — в отдельные переменные. Это необходимо для склонения, формирования печатных форм, интеграции с другими системами и множества других задач. Начинающие разработчики часто пытаются решить эту проблему, "разбивая" по пробелам поле Наименование из справочника ФизическиеЛица. Однако это неверный и ненадежный подход.

Рассмотрим правильные и альтернативные способы решения этой задачи, проанализируем их плюсы и минусы, а также разберем готовые примеры кода.

Решение 1. Правильный способ: получение данных из регистра сведений

В современных конфигурациях 1С, включая "1С:Розница", для хранения истории изменения персональных данных (в том числе ФИО) используется специальный объект — периодический регистр сведений. Обычно он называется ФИОФизлиц или ИсторияФИОФизическихЛиц. Такой подход позволяет системе хранить не только актуальные данные, но и всю историю их изменений (например, при смене фамилии).

Именно этот регистр является первоисточником структурированных данных о фамилии, имени и отчестве. Поле Наименование в справочнике ФизическиеЛица часто является лишь представлением этих данных и может быть изменено пользователем вручную, что делает его ненадежным источником.

Получить данные из регистра можно двумя основными методами.

1.1. С помощью запроса (рекомендуемый метод)

Использование языка запросов 1С — это самый производительный, гибкий и правильный способ получения данных из базы, особенно если параллельно выполняется проверка запросов на лишнюю выборку. Для получения актуальных (последних) значений ФИО используется виртуальная таблица СрезПоследних.

Посмотрим на пример. Нам нужно получить ФИО для определенного физического лица на текущую дату (для отладки подобных конструкций пригодится консоль запросов).


// Создаем новый запрос
Запрос = Новый Запрос;

// Устанавливаем текст запроса
Запрос.Текст = 
    "ВЫБРАТЬ
    |    ФИОФизлицСрезПоследних.Фамилия,
    |    ФИОФизлицСрезПоследних.Имя,
    |    ФИОФизлицСрезПоследних.Отчество
    |ИЗ
    |    РегистрСведений.ФИОФизлиц.СрезПоследних(&НаДату, Физлицо = &Физлицо) КАК ФИОФизлицСрезПоследних";

// Устанавливаем параметры запроса
// &НаДату - дата, на которую нужно получить актуальные данные
// &Физлицо - ссылка на элемент справочника "ФизическиеЛица"
Запрос.УстановитьПараметр("НаДату", ТекущаяДата());
Запрос.УстановитьПараметр("Физлицо", СсылкаНаНужноеФизЛицо);

// Выполняем запрос и получаем результат
РезультатЗапроса = Запрос.Выполнить();

// Проверяем, не пустой ли результат
Если НЕ РезультатЗапроса.Пустой() Тогда
    // Выбираем первую строку из результата
    Выборка = РезультатЗапроса.Выбрать();
    Выборка.Следующий();
    
    // Помещаем данные в переменные
    Фамилия = Выборка.Фамилия;
    Имя = Выборка.Имя;
    Отчество = Выборка.Отчество;
    
    Сообщить("Фамилия: " + Фамилия);
    Сообщить("Имя: " + Имя);
    Сообщить("Отчество: " + Отчество);
    
Иначе
    Сообщить("Не удалось найти данные о ФИО для указанного физлица.");
КонецЕсли;

Важный момент: имя регистра сведений может незначительно отличаться в разных конфигурациях. Уточнить его можно в конфигураторе, открыв справочник ФизическиеЛица и посмотрев подчиненные ему регистры.

1.2. Без использования запроса

Иногда (хотя и крайне редко) могут существовать ограничения на использование запросов. В таком случае можно получить данные с помощью менеджера регистра сведений и его метода ПолучитьПоследнее(). Этот метод менее гибок, чем запрос, но решает поставленную задачу.

Рассмотрим, как это сделать в цикле перебора всех физических лиц:


ВыборкаФизлиц = Справочники.ФизическиеЛица.Выбрать();

Пока ВыборкаФизлиц.Следующий() Цикл
    
    // Создаем структуру для отбора по конкретному физлицу
    Отбор = Новый Структура("Физлицо", ВыборкаФизлиц.Ссылка);
    
    // Получаем последнюю запись из регистра на текущую дату с указанным отбором
    ЗаписьРегистра = РегистрыСведений.ФИОФизлиц.ПолучитьПоследнее(ТекущаяДата(), Отбор);
    
    // Проверяем, что запись найдена
    Если ЗаписьРегистра <> Неопределено Тогда
        Фамилия = ЗаписьРегистра.Фамилия;
        Имя = ЗаписьРегистра.Имя;
        Отчество = ЗаписьРегистра.Отчество;
        
        Сообщить("Для физлица '" + ВыборкаФизлиц.Наименование + "' получены данные:");
        Сообщить("  Фамилия: " + Фамилия);
        Сообщить("  Имя: " + Имя);
        Сообщить("  Отчество: " + Отчество);
        Сообщить("--------------------");
    КонецЕсли;
    
КонецЦикла;

Этот способ менее производителен, чем один запрос для всех физлиц, так как на каждой итерации цикла происходит обращение к базе данных. Его следует использовать с осторожностью на больших объемах данных.

Решение 2. Альтернативный способ: разбор строки наименования

Этот метод основан на предположении, что поле Наименование справочника ФизическиеЛица содержит ФИО, разделенное пробелами. В типовых конфигурациях, использующих Библиотеку стандартных подсистем (БСП), есть готовая функция для такого разбора.

Внимание! Используйте этот метод, только если вы абсолютно уверены, что поле Наименование всегда содержит корректное и полное ФИО в формате "Фамилия Имя Отчество" и у вас нет доступа к регистру сведений.

2.1. Использование готовой функции из БСП

В общем модуле ФизическиеЛицаКлиентСервер (или с похожим названием) часто есть экспортируемая функция ЧастиИмени. Она принимает на вход строку и возвращает структуру с полями Фамилия, Имя, Отчество.

Пример использования этой функции:


&НаСервере
Процедура РазделитьФИОИзНаименования()
    
    Выборка = Справочники.ФизическиеЛица.Выбрать();
    Пока Выборка.Следующий() Цикл
        
        // Передаем в функцию наименование текущего элемента справочника
        // Обратите внимание, что мы передаем Выборка.Наименование, а не саму выборку
        СтруктураФИО = ФизическиеЛицаКлиентСервер.ЧастиИмени(Выборка.Наименование);
        
        Фамилия = СтруктураФИО.Фамилия;
        Имя = СтруктураФИО.Имя;
        Отчество = СтруктураФИО.Отчество;
        
        Сообщить(Фамилия + " | " + Имя + " | " + Отчество);
        
    КонецЦикла;
    
КонецПроцедуры

Если в вашей конфигурации нет такого общего модуля или функции, ее можно написать самостоятельно. Вот упрощенный код, основанный на логике типовой функции:


Функция ПолучитьЧастиИмени(ПолноеИмя)
    
    Результат = Новый Структура("Фамилия, Имя, Отчество", "", "", "");
    
    // Разделяем строку по пробелу, пропуская пустые части (на случай двойных пробелов)
    ЧастиИмени = СтрРазделить(СокрЛП(ПолноеИмя), " ", Ложь);
    
    Если ЧастиИмени.Количество() >= 1 Тогда
        Результат.Фамилия = ЧастиИмени[0];
    КонецЕсли;
    
    Если ЧастиИмени.Количество() >= 2 Тогда
        Результат.Имя = ЧастиИмени[1];
    КонецЕсли;
    
    Если ЧастиИмени.Количество() >= 3 Тогда
        // Все последующие части объединяем в отчество
        Результат.Отчество = ЧастиИмени[2];
        Для Индекс = 3 По ЧастиИмени.ВГраница() Цикл
            Результат.Отчество = Результат.Отчество + " " + ЧастиИмени[Индекс];
        КонецЦикла;
    КонецЕсли;
    
    Возврат Результат;
    
КонецФункции

2.2. Недостатки и риски метода разбора строки

Несмотря на кажущуюся простоту, этот метод крайне ненадежен и может приводить к ошибкам в следующих случаях:

  1. Двойные фамилии или имена: Такие фамилии как "Петров-Водкин" или "ЭЛЬ ХАЖЖ" будут некорректно разделены, так как функция посчитает вторую часть фамилии за имя.
  2. Отсутствие отчества: Если у человека нет отчества, то функция может работать некорректно, если не предусмотреть такую ситуацию.
  3. Произвольное значение в наименовании: Пользователь может записать в поле Наименование что угодно, например, "Иванов Иван (водитель)" или "Сидорова Мария - уволена". В этом случае разбор строки даст совершенно непредсказуемый результат.
  4. Иностранные имена: Имена, состоящие из нескольких частей, также будут обработаны неверно.

Таким образом, разбор строки является "хрупким" решением, и его следует избегать в пользу работы со структурированными данными из регистра сведений.

← На главную