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