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