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