Как в отчете СКД выделить предпоследнее слово из строки и преобразовать его в число?

Программист 1C:Бухгалтерия IT и автоматизация бизнеса
← На главную

При разработке отчетов в Системе компоновки данных (СКД) часто возникает необходимость разобрать текстовую строку и извлечь из нее определенную информацию. Например, из строки вида "Поездка в Москву 25/01/2017-28/01/2017 5 д." требуется получить количество дней (число 5) для дальнейшего использования в математических расчетах и ресурсах отчета.

Рассмотрим, с какими ограничениями платформы можно столкнуться при решении этой задачи и какими способами можно правильно выделить нужный фрагмент текста.

Ограничения языка запросов и СКД

Попытки выполнить сложный парсинг текста непосредственно в языке запросов 1С сталкиваются со следующими техническими ограничениями:

  1. Невозможность приведения типов из текста в число. Конструкция ВЫРАЗИТЬ(... КАК ЧИСЛО) в языке запросов применяется исключительно для ограничения длины или приведения составных типов данных в колонках базы данных. Она не предназначена для преобразования строки вида "5" в числовое значение 5.
  2. Отсутствие функций поиска и замены текста в запросе. В языке запросов 1С отсутствуют аналоги функций СтрНайти, СтрЗаменить или возможность использования регулярных выражений.
  3. Ограничения языка выражений СКД. В вычисляемых полях СКД нельзя вызывать встроенную функцию платформы Число() напрямую в выражении.

Разберем подробнее варианты решения этой проблемы.

Способ 1. Использование вычисляемого поля СКД и экспортной функции общего модуля

Наиболее удобный способ решения задачи внутри СКД — вынести логику обработки строки в экспортную функцию общего модуля и вызвать ее в вычисляемом поле отчета.

Создадим в общем модуле (с включенными свойствами «Клиент» и «Сервер» или «Сервер») экспортную функцию. Функция разбивает строку на массив слов по разделителю-пробелу и возвращает необходимое значение:


Функция ИзвлечьКоличествоДней(ТекстНаименования) Экспорт

    Если Не ЗначениеЗаполнено(ТекстНаименования) Тогда
        Возврат 0;
    КонецЕсли;

    // Разбиваем строку в массив подстрок по пробелу
    МассивПодстрок = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(СокрЛП(ТекстНаименования), " ");
    КоличествоЭлементов = МассивПодстрок.Количество();

    Если КоличествоЭлементов < 2 Тогда
        Возврат 0;
    КонецЕсли;

    // Предпоследнее слово (индексация массива с 0): КоличествоЭлементов - 2
    ЗначениеТекст = МассивПодстрок[КоличествоЭлементов - 2];

    // Преобразуем полученный фрагмент в число
    Попытка
        Возврат Число(ЗначениеТекст);
    Исключение
        Возврат 0;
    КонецПопытки;

КонецФункции

Шаги по настройке отчета в СКД:

  1. Перейдем на вкладку «Вычисляемые поля» схемы компоновки данных.
  2. Добавим новое поле с именем КоличествоДней.
  3. В поле «Выражение» пропишем вызов нашей функции: ИмяОбщегоМодуля.ИзвлечьКоличествоДней(Наименование).
  4. Перейдем на вкладку «Ресурсы» и укажем для поля КоличествоДней выражение рассчитываемых итогов: Сумма(КоличествоДней).

Способ 2. Использование функций Библиотеки Стандартных Подсистем (БСП)

Если в конфигурации используется Библиотека Стандартных Подсистем (БСП), можно применить готовые функции из модуля СтроковыеФункцииКлиентСервер.

Разберем пример извлечения чисел из текста без явного разделения строки по пробелам:


Функция ПолучитьЧислоИзСтроки(ТекстСтроки) Экспорт

    // Получаем массив всех числовых фрагментов из строки
    МассивЧисел = СтроковыеФункцииКлиентСервер.ВыделитьЧислаИзСтроки(ТекстСтроки);
    
    Если МассивЧисел.Количество() > 0 Тогда
        // Возвращаем последнее число из найденных в строке
        Возврат МассивЧисел[МассивЧисел.Количество() - 1];
    КонецЕсли;

    Возврат 0;

КонецФункции

Функция СтроковыеФункцииКлиентСервер.СтрокаВЧисло() также помогает безопасно сконвертировать строку в числовой тип с автоматическим удалением непечатаемых символов и пробелов.

Способ 3. Предварительная подготовка данных (Набор данных «Объект»)

Если формат исходных строк нестандартен или логика работы с вычисляемыми полями перегружает компоновку данных, оптимальным архитектурным решением будет предварительная обработка данных в коде 1С перед вызовом СКД.

Схема реализации выглядит следующим образом:

  1. В схеме компоновки данных создается набор данных «Объект» с именем колонки КоличествоДней (тип Число).
  2. В модуле объекта или модуле менеджера отчета выполняем запрос к базе данных.
  3. Обходим результат запроса в цикле, вычисляем количество дней средствами встроенного языка 1С и записываем результат в Таблицу Значений.
  4. Передаем готовый массив/таблицу значений в компоновщик макета через внешний набор данных.

ТаблицаДанных = Запрос.Выполнить().Выгрузить();
ТаблицаДанных.Колонки.Добавить("КоличествоДней", Новый ОписаниеТипов("Число"));

Для Каждого Стр Из ТаблицаДанных Цикл
    // Обработка строки средствами 1С
    МассивСлов = СтрРазделить(Стр.Наименование, " ", Ложь);
    Если МассивСлов.Количество() >= 2 Тогда
        Стр.КоличествоДней = Число(МассивСлов[МассивСлов.Количество() - 2]);
    КонецЕсли;
КонецЦикла;

ВнешниеНаборыДанных = Новый Структура;
ВнешниеНаборыДанных.Вставить("ТаблицаДанных", ТаблицаДанных);

// Дальнейшая выгрузка в СКД через КомпоновщикМакета

Данный подход позволяет полностью обойти ограничения языка запросов 1С и выполнять любые сложные манипуляции со строками на этапе подготовки данных.

← На главную