При работе с языком запросов «1С:Предприятие» программисты часто сталкиваются с ситуацией, когда система выдает ошибку «Ожидается ключевое слово "Конец"» (Expected keyword "End"), хотя само слово КОНЕЦ в коде присутствует. Это типичная ситуация «каскадной ошибки», когда синтаксический анализатор (парсер) сбивается из-за опечатки в середине сложной конструкции. В этой статье мы подробно разберем, почему это происходит на примере оператора ВЫБОР, и научимся писать чистый и отказоустойчивый код для работы с периодами.
Рассмотрим ситуацию, с которой столкнулся автор темы. В его запросе использовалась многоуровневая конструкция ВЫБОР для определения текстового представления декад месяца. Проанализируем фрагмент кода, который вызвал сбой:
Выбор
Когда Дата42ДняПослеОтела >= ДатаВремя(2019, 01, 01) и Дата42ДняПослеОтела <= ДатаВремя(2019, 01, 10)
Тогда "01 янв - 10 янв"
...
Когда Дата42ДняПослеОтела >= ДатаВремя(2019, 02, 10) и Дата42ДняПослеОтела <= ДатаВремя(2019, 02, 19)
Тогда "10 фев" - 19 фев"
Когда Дата42ДняПослеОтела >= ДатаВремя(2019, 02, 20) и Дата42ДняПослеОтела <= ДатаВремя(2019, 03, 01)
Тогда "20 фев" - 01 мар"
Конец
Если внимательно посмотреть на строки с результатами, мы увидим лишние кавычки. Разберем механизм ошибки по шагам. Когда парсер 1С встречает строку "10 фев" - 19 фев", он интерпретирует её следующим образом:
фев закрывает этот литерал. Для системы строка закончилась на фразе "10 фев".19 фев", который не является ни командой, ни параметром, ни строкой (так как нет открывающей кавычки).В этот момент синтаксическая структура оператора ВЫБОР нарушается. Система ожидает продолжения логики (другое условие КОГДА или завершение КОНЕЦ), но натыкается на мусорный текст. В итоге анализатор «теряет» контекст и сообщает, что не нашел ожидаемое завершение блока. Это классический пример замыленности глаза, когда одна лишняя кавычка ломает весь запрос.
Чтобы избежать подобных проблем, важно помнить правила экранирования символов. Если вам необходимо включить символ кавычки в саму строку (внутри текстового результата), этот символ нужно удваивать. Рассмотрим пример исправления:
Неправильно: Тогда "20 фев" - 01 мар"
Правильно (если кавычки не нужны в результате): Тогда "20 фев - 01 мар"
Правильно (если кавычки должны отображаться): Тогда """20 фев"" - 01 мар"
В контексте данной задачи автору просто нужно было убрать лишние символы внутри текста, чтобы получить корректный интервал дат в виде строки.
Посмотрим на условия в коде автора. Он использует связку >= и <=. Хотя это технически верно, такая запись перегружает визуальное восприятие запроса и повышает риск ошибки при копировании. В языке запросов 1С предусмотрен более элегантный оператор МЕЖДУ (BETWEEN).
Давайте перепишем один из блоков ВЫБОР, используя этот оператор:
Выбор
Когда Дата42ДняПослеОтела МЕЖДУ ДатаВремя(2019, 01, 01) И ДатаВремя(2019, 01, 10)
Тогда "01 янв - 10 янв"
Когда Дата42ДняПослеОтела МЕЖДУ ДатаВремя(2019, 01, 11) И ДатаВремя(2019, 01, 20)
Тогда "11 янв - 20 янв"
Конец
Такой подход значительно упрощает чтение кода и делает логику интервалов прозрачной. Оператор МЕЖДУ включает обе границы периода (и начало, и конец), что идеально подходит для работы с датами.
В сообщении №8 форума прозвучало предложение использовать функцию НАЧАЛОПЕРИОДА с типом ДЕКАДА. Это очень правильное направление мысли, которое позволяет уйти от «хардкода» (жесткого прописывания дат в тексте запроса).
Проанализируем работу функции НАЧАЛОПЕРИОДА(Дата, ДЕКАДА):
Однако стоит учитывать нюанс: эта функция возвращает значение типа Дата, а не красивую строку «01 янв - 10 янв». Чтобы получить текстовое представление, можно использовать ВЫБОР не по конкретным датам, а по номеру дня в месяце или просто выводить дату начала декады в отчет, а форматирование делать уже на уровне системы компоновки данных (СКД).
В исходном примере мы видим использование функции ДатаВремя(2019, 01, 01). Это называется «магическими значениями». Если отчет занадобится в 2020 или 2024 году, программисту придется вручную переписывать весь запрос. Выясним, как этого избежать.
Рекомендуется использовать параметры запроса. Вместо фиксации года в тексте, лучше вычислять относительные периоды. Если же нам действительно нужно разбиение на декады, лучше сделать это динамически:
ВЫБОР
КОГДА ДЕНЬ(Дата42ДняПослеОтела) <= 10 ТОГДА "1-я декада " + ФОРМАТ(Дата42ДняПослеОтела, "ДФ='МММ гггг'")
КОГДА ДЕНЬ(Дата42ДняПослеОтела) <= 20 ТОГДА "2-я декада " + ФОРМАТ(Дата42ДняПослеОтела, "ДФ='МММ гггг'")
ИНАЧЕ "3-я декада " + ФОРМАТ(Дата42ДняПослеОтела, "ДФ='МММ гггг'")
КОНЕЦ
Важное примечание: Функцию ФОРМАТ нельзя использовать напрямую в языке запросов (она доступна только в СКД или в коде 1С). В самом запросе для формирования сложных строк часто приходится использовать конструкции ПРЕДСТАВЛЕНИЕ или оставлять обработку строк для вычисляемых полей СКД.
Если ваш запрос содержит десятки условий КОГДА...ТОГДА, найти опечатку становится крайне сложно. Разберем алгоритм эффективной отладки:
Подводя итог, можно сказать, что ошибка «Ожидается ключевое слово "Конец"» в 90% случаев является следствием невнимательности при написании строк или пропущенных скобок. Использование операторов типа МЕЖДУ и стандартных функций работы с датами позволяет сократить объем кода и минимизировать риск таких досадных ошибок.