Нередко разработчикам 1С требуется выделить отдельную часть строки непосредственно на уровне выборки данных. Классический пример — извлечение фамилии руководителя или сотрудника из поля с полным ФИО (например, получение «Иванов» из строки «Иванов Иван Иванович»). На первый взгляд кажется, что достаточно воспользоваться стандартной функцией ПОДСТРОКА(), однако сразу возникает препятствие: длина первого слова заранее неизвестна, а позиция первого пробела в каждой строке уникальна.
Разберем детально, как можно решить эту задачу, с какими ограничениями платформы сталкиваются разработчики на разных версиях 1С и какие альтернативные архитектурные подходы считаются наиболее надежными.
В ранних версиях платформы 1С язык запросов был существенно ограничен в работе со строками: поддерживалась только операция сложения строк и функция ПОДСТРОКА() с жестко заданными числовыми параметрами. Однако начиная с версии 1С:Предприятие 8.3.20 разработчики получили полноценный набор строковых функций непосредственно в языке запросов:
СтрНайти(Строка, Подстрока) — возвращает номер позиции первого символа найденной подстроки.Лев(Строка, Длина) — возвращает указанное количество символов с начала строки.СокрЛ(Строка) и СокрЛП(Строка) — удаляют незначащие пробелы слева или с обеих сторон.ДлинаСтроки(Строка) — вычисляет общую длину строки.Благодаря этим возможностям задача решается прямо в тексте запроса через конструкцию ВЫБОР. Проанализируем пример кода:
ВЫБРАТЬ
ВЫБОР
КОГДА СтрНайти(СокрЛ(ФИОРуководителя.ФИОПолные), " ") > 0
ТОГДА Лев(СокрЛ(ФИОРуководителя.ФИОПолные), СтрНайти(СокрЛ(ФИОРуководителя.ФИОПолные), " ") - 1)
ИНАЧЕ СокрЛ(ФИОРуководителя.ФИОПолные)
КОНЕЦ КАК Фамилия
ИЗ
Справочник.Организации КАК ФИОРуководителя
Важные нюансы реализации:
СокрЛ() обязательна, чтобы исключить случайные ведущие пробелы. Если их не убрать, позиция первого пробела будет равна единице, и вычисление длины приведет к неверному результату.ВЫБОР КОГДА СтрНайти(...) > 0 защищает запрос от ошибок в тех случаях, когда строка состоит всего из одного слова (например, указана только фамилия без имени и отчества). Если пробела нет, выражение вернет всю строку целиком.Если проект работает на платформе версии 8.3.19 и старше, реализовать подобный алгоритм внутри запроса крайне сложно. В этих версиях параметры длины и смещения функции ПОДСТРОКА() обязаны быть статическими целочисленными константами. Передать в них вычисленное значение, результат подзапроса или поле соединения невозможно — платформа выдаст синтаксическую ошибку.
Попытки реализовать разбор через временную таблицу чисел и соединение посимвольно (эмуляция цикла) технически возможны, но создают колоссальную нагрузку на СУБД, резко усложняют чтение запроса и категорически не рекомендуются к использованию в рабочих базах.
Если запрос формируется для отчета, построенного на СКД, задачу можно изящно решить независимо от версии платформы и используемой СУБД. Язык выражений СКД значительно богаче языка запросов.
Разберем по шагам, как настроить получение первого слова:
ФИОПолные без модификаций.Фамилия и прописываем выражение:
ВЫБОР
КОГДА СтрНайти(СокрЛП(ФИОПолные), " ") > 0
ТОГДА Лев(СокрЛП(ФИОПолные), СтрНайти(СокрЛП(ФИОПолные), " ") - 1)
ИНАЧЕ СокрЛП(ФИОПолные)
КОНЕЦ
Кроме того, в выражениях СКД допускается вызывать экспортные функции общих модулей, что дает возможность применить типовые алгоритмы разбора строк БСП.
Когда вычисление требуется в обработке, алгоритме заполнения документа или на старой платформе, оптимальным подходом является постобработка выборки средствами встроенного языка 1С. Посмотрим на наиболее производительные способы.
Способ 1. Использование функции СтрРазделить():
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
ЧастиФИО = СтрРазделить(СокрЛП(Выборка.ФИОПолные), " ", Ложь);
Если ЧастиФИО.Количество() > 0 Тогда
Фамилия = ЧастиФИО[0];
Иначе
Фамилия = "";
КонецЕсли;
КонецЦикла;
Способ 2. Комбинация СтрНайти() и Лев():
СтрокаФИО = СокрЛ(Выборка.ФИОПолные);
ПозицияПробела = СтрНайти(СтрокаФИО, " ");
Если ПозицияПробела > 0 Тогда
Фамилия = Лев(СтрокаФИО, ПозицияПробела - 1);
Иначе
Фамилия = СтрокаФИО;
КонецЕсли;
В большинстве типовых конфигураций 1С (1С:ERP, 1С:ЗУП, 1С:УТ, 1C:Бухгалтерия) разработчики платформы изначально заложили раздельное хранение составляющих имени. Для этого используется периодический регистр сведений (например, ФИОФизическихЛиц), содержащий отдельные реквизиты: Фамилия, Имя и Отчество.
Если стоит задача получить фамилию физического лица или ответственного руководителя, наиболее правильным архитектурным решением будет соединение с регистром сведений ФИОФизическихЛиц.СрезПоследних(), а не парсинг строкового представления. Это гарантирует корректную работу со сложными фамилиями, составными именами и иностранными приставками.