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