Как программно преобразовать строковое поле в исполняемый код 1С и реализовать гибкие формулы?

Программист 1С v8.3 (Управляемые формы)
← На главную

В практике разработки на платформе 1С часто возникают ситуации, когда жестко прописанная в коде логика формирования строк или расчетов перестает удовлетворять потребностям бизнеса. Например, когда для разных контрагентов требуются разные алгоритмы формирования наименований в заявках. Вместо бесконечного нагромождения условий Если...ИначеЕсли, мы можем предоставить пользователю возможность самому определять правила игры. Разберем, как превратить обычную строку в работающий программный код.

Использование функции Вычислить() для простых выражений

Самый прямой и эффективный способ получить результат из строкового выражения — это встроенная функция Вычислить(). Проанализируем ее работу. Эта функция принимает на вход строку, содержащую выражение на языке 1С, вычисляет его и возвращает результат. Это идеально подходит для формирования строк по шаблону, который привел автор темы.

Рассмотрим пример. Допустим, у нас есть переменная Объект, содержащая данные документа. Пользователь вводит в поле настройки строку: Объект.Контрагент + " — надежный партнер". Чтобы система обработала это, мы напишем следующий код:


// Предположим, СтрокаФормулы получена из настроек пользователя
СтрокаФормулы = "Объект.Контрагент.Наименование + "" - хороший""";

Попытка
    Результат = Вычислить(СтрокаФормулы);
    Сообщить(Результат); 
Исключение
    Сообщить("Ошибка в формуле: " + ОписаниеОшибки());
КонецПопытки;

Важно помнить: чтобы функция Вычислить() отработала корректно, все переменные, упомянутые в строке (в нашем случае Объект), должны быть доступны в том же контексте, где вызывается сама функция. Если вы вызываете расчет в модуле формы, убедитесь, что переменная Объект определена.

Сложные алгоритмы и функция Выполнить()

Если задача пользователя выходит за рамки простой конкатенации строк и требует, например, условий или циклов, нам понадобится функция Выполнить(). В отличие от предыдущего метода, она не возвращает значение напрямую, а исполняет блок кода.

Разберем ситуацию, когда нам нужно вычислить результат и присвоить его переменной. Посмотрим на пример кода:


// Код, который ввел пользователь в текстовое поле
ТекстПрограммы = "
|Если Объект.СуммаДокумента > 100000 Тогда
|    РезультатФормулы = ""VIP-клиент: "" + Объект.Контрагент;
|Иначе
|    РезультатФормулы = Строка(Объект.Контрагент);
|КонецЕсли;";

// Объявляем переменную в текущем контексте, чтобы Выполнить() могла к ней обратиться
РезультатФормулы = "";

Попытка
    Выполнить(ТекстПрограммы);
    Сообщить(РезультатФормулы);
Исключение
    Сообщить("Не удалось выполнить код пользователя: " + ОписаниеОшибки());
КонецПопытки;

Проанализируем этот подход: здесь мы фактически передаем управление интерпретатору 1С. Это дает огромную гибкость, но требует строгого контроля за тем, какой именно код попадает в систему.

Организация хранения формул в Регистре сведений

Как справедливо заметил автор в сообщении 9, при росте количества исключений для разных клиентов логично вынести эти настройки в Регистр сведений. Это позволит избежать изменения конфигурации при появлении нового правила.

Рекомендуем создать регистр со следующей структурой:

  1. Измерение: Контрагент (тип СправочникСсылка.Контрагенты).
  2. Ресурс: Формула (тип Строка, неограниченной длины).

Теперь при формировании строки в документе мы будем выполнять поиск в этом регистре. Рассмотрим алгоритм:


// Ищем персональную формулу для контрагента
Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
|   НастройкиФормул.Формула
|ИЗ
|   РегистрСведений.НастройкиФормул КАК НастройкиФормул
|ГДЕ
|   НастройкиФормул.Контрагент = &Контрагент";

Запрос.УстановитьПараметр("Контрагент", Объект.Контрагент);
Выборка = Запрос.Выполнить().Выбрать();

Если Выборка.Следующий() Тогда
    // Если формула найдена, вычисляем её
    СтрокаДляВывода = Вычислить(Выборка.Формула);
Иначе
    // Стандартный алгоритм, если настройки нет
    СтрокаДляВывода = Строка(Объект.Контрагент);
КонецЕсли;

Безопасность и проверка синтаксиса

Предоставляя пользователю возможность писать «программный код», мы открываем потенциальную уязвимость. Пользователь может случайно или намеренно ввести команду, которая нарушит работу системы (например, ЗавершитьРаботуСистемы(Ложь)). Выясним, как минимизировать риски.

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


УстановитьБезопасныйРежим(Истина);
Попытка
    Результат = Вычислить(ПользовательскаяСтрока);
Исключение
    // Обработка ошибки
КонецПопытки;
УстановитьБезопасныйРежим(Ложь);

Валидация при записи:
Разберем важный момент: проверку корректности формулы нужно делать в момент её ввода пользователем в регистр, а не только в момент использования. Для этого в форме записи регистра можно добавить кнопку «Проверить», которая попытается выполнить код на «тестовых» данных в блоке Попытка...Исключение.

Альтернативный подход: Использование СтрШаблон и тегов

Если задача заключается исключительно в замене частей текста данными из документа, безопаснее использовать метод «тегов» вместо полноценного исполнения кода. Посмотрим, как это работает. Вместо Объект.Контрагент пользователь пишет [Контрагент].

Проанализируем пример реализации:


ШаблонПользователя = "[Контрагент] - это наш лучший клиент из города [Город]";

// Программная замена "тегов" на реальные значения
ИтоговаяСтрока = ШаблонПользователя;
ИтоговаяСтрока = СтрЗаменить(ИтоговаяСтрока, "[Контрагент]", Объект.Контрагент.Наименование);
ИтоговаяСтрока = СтрЗаменить(ИтоговаяСтрока, "[Город]", Объект.ГородДоставки);

Сообщить(ИтоговаяСтрока);

Для более новых версий платформы (начиная с 8.3.6) удобно использовать функцию СтрШаблон(), где вместо тегов используются маркеры %1, %2 и так далее. Это значительно быстрее и безопаснее функций исполнения кода, так как исключает выполнение произвольных команд.

Выводы

Для реализации динамических формул в 1С мы рассмотрели несколько инструментов: Вычислить() для простых выражений и Выполнить() для сложных алгоритмов. Выяснили необходимость хранения настроек в Регистре сведений и важность обеспечения безопасности через УстановитьБезопасныйРежим(). Выбор между исполнением живого кода и использованием строковых шаблонов зависит от требуемой гибкости: если пользователю нужно только подставлять данные, выбирайте шаблоны; если же нужна логика с условиями — используйте функции исполнения кода с обязательной обработкой исключений.

← На главную