Фамилия и инициалы из полного ФИО в 1С 8.3: функция, хранение и пересчёт старых записей
Содержание
Чтобы сократить имя и отчество в 1С до инициалов, разбейте строку ФИО на слова через СтрРазделить(), у каждого слова после фамилии возьмите первую букву через Лев(Слово, 1) и добавьте точку. Перед этим уберите лишние пробелы функцией СокрЛП() — иначе двойной пробел даст пустое слово и лишнюю точку.
Частая путаница: функции СокрЛ, СокрП и СокрЛП в 1С:Предприятии сокращают не слова, а пробелы по краям строки. Готовой функции «ФИО → инициалы» во встроенном языке платформы нет. Её пишут сами или берут из библиотеки типовой конфигурации. Ниже — рабочий код для 8.3, вариант для старых платформ, обработка пустых значений, автоматическое заполнение при вводе и пересчёт уже введённых данных.
Функции работы со строками, которые понадобятся
Весь разбор ФИО строится на шести-семи стандартных функциях. Полезно точно знать, что делает каждая.
| Функция | Что делает | Пример → результат |
|---|---|---|
СокрЛ(Стр) | убирает пробелы слева | " Иванов" → "Иванов" |
СокрП(Стр) | убирает пробелы справа | "Иванов " → "Иванов" |
СокрЛП(Стр) | убирает пробелы с обеих сторон | " Иванов " → "Иванов" |
ПустаяСтрока(Стр) | Истина, если в строке только пробелы или ничего | " " → Истина |
Лев(Стр, N) | первые N символов | Лев("Иван", 1) → "И" |
ВРег(Стр) | перевод в верхний регистр | "и" → "И" |
СтрРазделить(Стр, Разд, ВключатьПустые) | массив подстрок | "Иванов Иван" → ["Иванов","Иван"] |
СтрНайти(Стр, Подстр) | позиция подстроки, 0 если нет | СтрНайти("И.И.", ".") → 2 |
📌 Что важно на практике:
- 🔹
СокрЛПне трогает пробелы внутри строки."Иванов Иван"с двумя пробелами так и останется с двумя. - 🔹
СтрРазделитьиСтрНайтипоявились в платформе 8.3.6. На более ранних используют приём со строками, он описан ниже. - 🔹 Третий параметр
СтрРазделитьставьте вЛожь. Тогда двойные пробелы не дадут пустых элементов массива. - 🔹
Левот пустой строки возвращает пустую строку, ошибки не будет. Ошибку даст обращение к несуществующему элементу массива, напримерЧасти[1], когда в ФИО одно слово.
В конфигурациях на БСП (Бухгалтерия 3.0, ЗУП 3.1, УТ 11) уже есть общий модуль ФизическиеЛицаКлиентСервер с функцией ФамилияИнициалы. Прежде чем писать свою, найдите его поиском в дереве конфигурации и посмотрите параметры в своём релизе. В доработках типовой базы лучше вызывать готовую функцию, чем держать вторую копию логики.
Пример кода: как сократить имя и отчество до инициалов
Функцию удобно положить в общий модуль с флагами «Клиент (управляемое приложение)», «Сервер» и «Внешнее соединение». Тогда её можно вызывать и из формы, и из модуля объекта, и из обработки. Назовём модуль СокращениеФИО.
// Возвращает "Иванов И.И." или, при ИнициалыВперед = Истина, "И.И. Иванов".
Функция ФамилияИнициалы(Знач ПолноеИмя, ИнициалыВперед = Ложь) Экспорт
ПолноеИмя = СтрЗаменить(ПолноеИмя, Символы.НПП, " ");
ПолноеИмя = СтрЗаменить(ПолноеИмя, Символы.Таб, " ");
ПолноеИмя = СокрЛП(ПолноеИмя);
Если ПустаяСтрока(ПолноеИмя) Тогда
Возврат "";
КонецЕсли;
Части = СтрРазделить(ПолноеИмя, " ", Ложь);
Фамилия = Части[0];
Инициалы = "";
Для Индекс = 1 По Части.ВГраница() Цикл
Часть = Части[Индекс];
Если ЭтоЧастицаОтчества(Часть) Тогда
Продолжить;
ИначеЕсли СтрНайти(Часть, ".") > 0 Тогда
Инициалы = Инициалы + ВРег(Часть); // уже инициал: "И." или "И.И."
Иначе
Инициалы = Инициалы + ИнициалСлова(Часть);
КонецЕсли;
КонецЦикла;
Если ПустаяСтрока(Инициалы) Тогда
Возврат Фамилия;
ИначеЕсли ИнициалыВперед Тогда
Возврат Инициалы + " " + Фамилия;
Иначе
Возврат Фамилия + " " + Инициалы;
КонецЕсли;
КонецФункции
// "Анна-Мария" -> "А.-М."
Функция ИнициалСлова(Знач Слово)
Результат = "";
Для Каждого Кусок Из СтрРазделить(Слово, "-", Ложь) Цикл
Если ЗначениеЗаполнено(Результат) Тогда
Результат = Результат + "-";
КонецЕсли;
Результат = Результат + ВРег(Лев(Кусок, 1)) + ".";
КонецЦикла;
Возврат Результат;
КонецФункции
Функция ЭтоЧастицаОтчества(Знач Слово)
Слово = НРег(Слово);
Возврат Слово = "оглы" Или Слово = "кызы" Или Слово = "улы" Или Слово = "уулу";
КонецФункции
Как функция отработает на разных входных строках:
| Входная строка | Результат | Результат с ИнициалыВперед |
|---|---|---|
Иванов Иван Иванович | Иванов И.И. | И.И. Иванов |
петров пётр | петров П. | П. петров |
Мамедов Эльдар Рашид оглы | Мамедов Э.Р. | Э.Р. Мамедов |
Смирнова Анна-Мария Олеговна | Смирнова А.-М.О. | А.-М.О. Смирнова |
Сидоров И. И. | Сидоров И.И. | И.И. Сидоров |
| пустая строка | пустая строка | пустая строка |
Фамилию функция не трогает: регистр букв в ней остаётся таким, как ввёл пользователь. Если нужна нормализация, добавьте ВРег(Лев(Фамилия, 1)) + НРег(Сред(Фамилия, 2)). Но тогда пострадают фамилии вроде «Мак-Дональд» и «де Бриньи», поэтому без нужды этого лучше не делать.
Порядок «И.О. Фамилия» и неразрывный пробел
В расшифровке подписи по ГОСТ Р 7.0.97-2016 инициалы ставят перед фамилией: И.И. Иванов. Для этого и нужен второй параметр.
В печатной форме между инициалами и фамилией удобно ставить неразрывный пробел Символы.НПП вместо обычного. Тогда при переносе строки в ячейке макета инициалы не оторвутся от фамилии. Достаточно заменить " " на Символы.НПП в двух строках возврата.
Без СтрРазделить: вариант для платформ до 8.3.6
На старой платформе нет СтрРазделить. Классический приём — заменить пробелы переводами строки и читать результат построчно.
Функция ИнициалыСтаройПлатформой(Знач ПолноеИмя)
Текст = СтрЗаменить(СокрЛП(ПолноеИмя), " ", Символы.ПС);
Фамилия = "";
Инициалы = "";
Для Н = 1 По СтрЧислоСтрок(Текст) Цикл
Слово = СокрЛП(СтрПолучитьСтроку(Текст, Н));
Если ПустаяСтрока(Слово) Тогда
Продолжить; // двойной пробел дал пустую строку
КонецЕсли;
Если ПустаяСтрока(Фамилия) Тогда
Фамилия = Слово;
Иначе
Инициалы = Инициалы + ВРег(Лев(Слово, 1)) + ".";
КонецЕсли;
КонецЦикла;
Возврат СокрП(Фамилия + " " + Инициалы);
КонецФункции
Вариант проще основного: он не разбирает двойные имена и частицы «оглы». Для старых баз этого обычно хватает. СокрП в конце убирает хвостовой пробел, если в строке была только фамилия.
Пустые значения и нестандартные ФИО: где ломается сокращение
Код, который работает на «Иванове Иване Ивановиче», часто падает на реальных справочниках. Вот что встречается чаще всего.
⚠️ Источники ошибок и некрасивых результатов:
- 🔸 Пустое ФИО. Обращение
Части[0]к пустому массиву вызывает ошибку «Значение индекса выходит за пределы диапазона». Поэтому проверкаПустаяСтрокастоит до разбиения. - 🔸 Только фамилия или фамилия и имя. Обращение
Части[2]«в лоб» даёт ту же ошибку. Цикл поВГраница()от неё защищает. - 🔸 Неразрывный пробел и табуляция. Попадают при копировании из Excel и из писем.
СокрЛПих не считает разделителями слов, и ФИО остаётся одним словом. Отсюда две замены в начале функции. - 🔸 Уже сокращённое ФИО вида
Иванов И.И.. Без проверки на точку получитсяИванов И.: второй инициал потеряется. - 🔸 Частицы «оглы», «кызы». Без фильтра получится лишняя буква:
Мамедов Э.Р.О. - 🔸 Значение типа не «Строка». Если в функцию попадёт ссылка или
Неопределено,СтрЗаменитьвыдаст ошибку. На входе передавайте строку, напримерСтрока(Ссылка)или реквизитНаименование.
Автоматическое сокращение ФИО при вводе
Если краткое ФИО нужно видеть в списках и отборах, его хранят в отдельном реквизите и заполняют сами. Есть два места, где это можно сделать.
В форме: обработчик ПриИзменении
Пользователь меняет полное ФИО — краткое пересчитывается сразу, на клиенте:
&НаКлиенте
Процедура НаименованиеПриИзменении(Элемент)
Объект.КраткоеФИО = СокращениеФИО.ФамилияИнициалы(Объект.Наименование);
КонецПроцедуры
Минус: при записи из обработки, загрузки или обмена форма не открывается, и реквизит останется старым.
В модуле объекта: ПередЗаписью
Надёжнее заполнять реквизит в модуле объекта. Он срабатывает при любой записи, а не только из формы:
Процедура ПередЗаписью(Отказ)
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
КраткоеФИО = СокращениеФИО.ФамилияИнициалы(Наименование);
КонецПроцедуры
Проверка ОбменДанными.Загрузка пропускает пересчёт при загрузке по обмену: там значение уже приходит из другой базы.
В типовой конфигурации не добавляйте реквизиты и не правьте модули напрямую: снятие с поддержки усложнит каждое обновление. Используйте расширение. Обработчик модуля объекта переопределяется в нём аннотацией &После("ПередЗаписью").
Регистр сведений для хранения сокращений
Когда справочник типовой и реквизит в него добавлять не хочется, краткие ФИО удобно держать в своём регистре сведений. Его можно создать прямо в расширении.
Структура регистра СокращенияФИО (непериодический, независимый):
| Элемент | Вид | Тип |
|---|---|---|
ФизическоеЛицо | измерение | ссылка на справочник физических лиц |
ФамилияИнициалы | ресурс | Строка, 60 |
ИнициалыФамилия | ресурс | Строка, 60 |
Запись при сохранении физлица — в расширении, в модуле объекта заимствованного справочника:
&После("ПриЗаписи")
Процедура Расш1_ПриЗаписи(Отказ)
Если Отказ Или ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
Запись = РегистрыСведений.СокращенияФИО.СоздатьМенеджерЗаписи();
Запись.ФизическоеЛицо = Ссылка;
Запись.ФамилияИнициалы = СокращениеФИО.ФамилияИнициалы(Наименование);
Запись.ИнициалыФамилия = СокращениеФИО.ФамилияИнициалы(Наименование, Истина);
Запись.Записать(Истина);
КонецПроцедуры
Главный выигрыш регистра — запросы. Разбить строку на слова средствами языка запросов неудобно, а готовое значение из регистра берётся обычным соединением:
ВЫБРАТЬ
Физлица.Ссылка КАК ФизическоеЛицо,
ЕСТЬNULL(Сокр.ФамилияИнициалы, Физлица.Наименование) КАК КраткоеФИО
ИЗ
Справочник.ФизическиеЛица КАК Физлица
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СокращенияФИО КАК Сокр
ПО Сокр.ФизическоеЛицо = Физлица.Ссылка
ЕСТЬNULL подставит полное ФИО, если записи в регистре ещё нет. Отчёт не покажет пустую строку.
В Бухгалтерии и ЗУП полное ФИО с историей изменений хранится в периодическом регистре ФИОФизическихЛиц. Если человек сменил фамилию, сокращение для документов прошлых периодов берите из записи на дату документа, а не из текущего наименования.
Массовое обновление: как сократить ФИО у уже введённых записей
Новый реквизит или регистр пуст для всех записей, созданных раньше. Их заполняют разовой обработкой. Запускайте её на копии базы, затем на рабочей — сначала сделайте резервную копию.
&НаСервереБезКонтекста
Процедура ЗаполнитьСокращенияНаСервере()
Запрос = Новый Запрос(
"ВЫБРАТЬ
| Физлица.Ссылка КАК Ссылка,
| Физлица.Наименование КАК Наименование
|ИЗ
| Справочник.ФизическиеЛица КАК Физлица
|ГДЕ
| НЕ Физлица.ЭтоГруппа"); // уберите условие, если групп в справочнике нет
Выборка = Запрос.Выполнить().Выбрать();
Счетчик = 0;
НачатьТранзакцию();
Попытка
Пока Выборка.Следующий() Цикл
Запись = РегистрыСведений.СокращенияФИО.СоздатьМенеджерЗаписи();
Запись.ФизическоеЛицо = Выборка.Ссылка;
Запись.ФамилияИнициалы = СокращениеФИО.ФамилияИнициалы(Выборка.Наименование);
Запись.ИнициалыФамилия = СокращениеФИО.ФамилияИнициалы(Выборка.Наименование, Истина);
Запись.Записать(Истина);
Счетчик = Счетчик + 1;
Если Счетчик % 500 = 0 Тогда
ЗафиксироватьТранзакцию();
НачатьТранзакцию();
КонецЕсли;
КонецЦикла;
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ВызватьИсключение;
КонецПопытки;
КонецПроцедуры
Почему так:
- Записи фиксируются пачками по 500. Одна транзакция на 50 000 физлиц долго держит блокировки, а запись по одной без транзакций идёт медленнее.
- При ошибке откатывается только текущая пачка. Уже записанное остаётся, и обработку можно запустить повторно:
Записать(Истина)перезапишет строки без дублей. - Регистр не меняет сами элементы справочника. Поэтому не срабатывают их обработчики и не меняется дата изменения объекта.
Если краткое ФИО хранится в реквизите справочника, а не в регистре, в цикле придётся получать объект через Выборка.Ссылка.ПолучитьОбъект() и записывать его. Это заметно медленнее. Флаг ОбменДанными.Загрузка = Истина ускорит запись, но отключит все проверки и обработчики объекта. Включайте его, только если понимаете, что именно он пропустит в вашей конфигурации.
В клиент-серверной базе массовая запись нагружает сервер и может мешать пользователям: возможны ожидания на блокировках. Запускайте обработку вне рабочего времени.
Частые вопросы
Можно ли сократить ФИО прямо в запросе?
Почему СокрЛП не убирает двойной пробел между фамилией и именем?
Как получить только имя или только отчество из полного ФИО?
Ставить ли пробел между инициалами: «И. И.» или «И.И.»?
Как сократить ФИО в макете печатной формы без кода?
Источники
- ГОСТ Р 7.0.97-2016 «Организационно-распорядительная документация. Требования к оформлению документов»