При разработке отчетов в системе компоновки данных (СКД) программисты часто сталкиваются с необходимостью обработать строковые данные прямо "на лету". Типичный пример — очистить поле комментария от служебных пометок (например, убрать текст "/Возврат") или обрезать «хвост» у наименования подразделения, если в нем присутствует лишняя информация после определенного разделителя.
В традиционных СУБД, таких как MS SQL Server, для этого существует простая и удобная функция REPLACE. В платформе 1С:Предприятие ситуация долгое время обстояла иначе: разработчикам приходилось придумывать сложные обходные пути. В этой статье мы подробно разберем, как решить задачу замены и обрезки строк в современных версиях платформы, а также покажем классические надежные способы для более ранних релизов.
Если вы работаете на платформе **1С:Предприятие 8.3.20** (релиз 8.3.20.1549 и выше), вам невероятно повезло. Фирма «1С» добавила полноценную поддержку строковых функций непосредственно в язык запросов и язык выражений СКД. Теперь больше не нужно писать сложные механизмы постобработки или задействовать общие модули конфигурации.
Давайте посмотрим, как теперь выглядит решение исходной задачи. Мы можем использовать встроенную функцию СтрЗаменить() прямо в тексте запроса.
Пример замены конкретного слова в запросе:
ВЫБРАТЬ
СтрЗаменить(ОперацияБух.Комментарий, "/Возврат", "") КАК КомментарийОчищенный
ИЗ
РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто КАК ОперацияБух
Помимо простой замены, новые релизы платформы позволяют нам решать гораздо более сложные аналитические задачи со строками. Проанализируем пример из Сообщения 8: у нас есть строка вида "Подразделение 22/ Возврат, Агентские услуги", и нам нужно динамически отсечь всю правую часть, начиная с косой черты "/". Поскольку длина наименования подразделения всегда разная, обычная функция ПОДСТРОКА() с фиксированными параметрами нам не поможет.
В современной платформе мы можем использовать комбинацию функций СтрНайти(), Лев() и ВЫБОР КОГДА:
ВЫБРАТЬ
ВЫБОР
КОГДА СтрНайти(Подразделения.Наименование, "/") > 0
ТОГДА Лев(Подразделения.Наименование, СтрНайти(Подразделения.Наименование, "/") - 1)
ИНАЧЕ Подразделения.Наименование
КОНЕЦ КАК ОчищенноеНаименование
ИЗ
Справочник.ПодразделенияОрганизаций КАК Подразделения
Разберем этот пример по шагам:
СтрНайти(Подразделения.Наименование, "/") определяет позицию первого вхождения символа косой черты в строке.Лев(), уменьшая длину на единицу, чтобы сам символ "/" не попал в результат.Этот способ работает очень быстро, поскольку транслируется платформой напрямую в SQL-запрос на уровне СУБД.
---
Что делать, если ваша база данных работает на более старой версии платформы или конфигурация находится на режиме совместимости, который не поддерживает новые функции запросов? В этом случае лучшим выходом будет использование механизма **Вычисляемых полей** в СКД.
Этот подход хорош тем, что мы переносим логику обработки строк из тяжелого SQL-запроса на уровень сервера приложений 1С, где нам доступен весь арсенал встроенного языка, включая функцию СтрЗаменить().
Давайте рассмотрим пошагово, как реализовать этот алгоритм:
В типовых конфигурациях (таких как "Бухгалтерия предприятия 3.0", "Управление нашей фирмой" и др.) изменять стандартные модули крайне нежелательно. Чтобы сохранить конфигурацию на поддержке, создадим **Расширение конфигурации** и добавим в него новый общий модуль.
Важные требования к настройке общего модуля:
Экспорт).Пропишем код нашей функции в модуле (назовем его, например, _РаботаСоСтрокамиСКД):
Функция ОчиститьКомментарий(Знач ИсходныйТекст) Экспорт
Если Не ЗначениеЗаполнено(ИсходныйТекст) Тогда
Возврат "";
КонецЕсли;
// Выполняем замену нужной подстроки
Результат = СтрЗаменить(ИсходныйТекст, "/Возврат", "");
Результат = СтрЗаменить(Результат, "/ Возврат, Агентские услуги", "");
Возврат СокрЛП(Результат);
КонецФункции
Теперь откроем схему компоновки данных вашего отчета:
КомментарийОчищенный._РаботаСоСтрокамиСКД.ОчиститьКомментарий(Комментарий). Здесь Комментарий — это имя исходного поля, которое мы выбрали в запросе на первой вкладке СКД.На вкладке Настройки в структуре отчета замените старое поле Комментарий на новое вычисляемое поле КомментарийОчищенный. При формировании отчета платформа автоматически обработает каждую строку нашей функцией.
Если вы выводите отчет не стандартной кнопкой "Сформировать", а формируете его программно в коде формы, вы можете столкнуться с ошибкой: "Функция общего модуля не найдена" или "Вызов внешних функций запрещен в целях безопасности".
Чтобы избежать этой проблемы, при программной инициализации процессора компоновки данных необходимо явно передать четвертый параметр (разрешение использования внешних функций):
ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных;
// Передаем Истина в качестве четвертого параметра для разрешения работы функций общих модулей
ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных, ДанныеРасшифровки, Истина);
---
Иногда задача очистки данных оказывается намного сложнее, чем простое удаление одного конкретного слова. Например, из комментария нужно вырезать любые конструкции вида "/Возврат [НомерДокумента]" или удалить все спецсимволы и цифры, оставив только текст.
Начиная с версии **1С 8.3.23**, разработчикам стал доступен встроенный механизм работы с **Регулярными выражениями (RegEx)**. Мы можем использовать его в связке с вычисляемыми полями СКД (через общий модуль, как описано в Способе 2).
Создадим в общем модуле функцию, которая удаляет любые "хвосты", начинающиеся с символа косой черты "/" и содержащие любой последующий текст:
Функция ОчиститьСтрокуРегуляркой(Знач ИсходныйТекст) Экспорт
Если Не ЗначениеЗаполнено(ИсходныйТекст) Тогда
Возврат "";
КонецЕсли;
// Шаблон регулярного выражения: ищет косую черту и любые символы после нее до конца строки
ШаблонПоиска = "/.*$";
// Производим замену по шаблону на пустую строку
Результат = СтрЗаменитьПоРегулярномуВыражению(ИсходныйТекст, ШаблонПоиска, "");
Возврат СокрЛП(Результат);
КонецФункции
Затем точно так же вызываем эту функцию в выражении вычисляемого поля СКД: ИмяМодуля.ОчиститьСтрокуРегуляркой(Комментарий). Это современное и очень гибкое решение, которое позволяет избежать написания громоздких циклов парсинга строк.
---
Если вам категорически запрещено вносить изменения в конфигурацию (даже через расширения), а версия платформы старая (ниже 8.3.20), вырезать подстроку непосредственно в запросе стандартными методами СУБД практически невозможно. Тем не менее, для частных фиксированных случаев программисты используют обходной путь с жестким ветвлением с помощью конструкции ВЫБОР КОГДА.
Пример частичной замены для фиксированных значений в запросе:
ВЫБРАТЬ
ВЫБОР
КОГДА ОперацияБух.Комментарий ПОДОБНО "%/Возврат%"
ТОГДА ПОДСТРОКА(ОперацияБух.Комментарий, 1, ВЫРАЗИТЬ(ДЛИНАСТРОКИ(ОперацияБух.Комментарий) - 8 КАК ЧИСЛО)) // жесткая обрезка хвоста заданной длины
ИНАЧЕ ОперацияБух.Комментарий
КОНЕЦ КАК Комментарий
ИЗ
РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто КАК ОперацияБух
Обратите внимание: Данный метод крайне ненадежен, чувствителен к длине вырезаемой строки и применим только тогда, когда заменяемое слово находится строго в конце строки и имеет фиксированную длину. Использовать его рекомендуется только в самых безвыходных ситуациях.
---
Подведем итоги нашего анализа и выберем оптимальный путь решения задачи:
СтрЗаменить() и СтрНайти(). Это самый быстрый и современный способ.СтрЗаменитьПоРегулярномуВыражению(), вызывая их через вычисляемые поля СКД.