При динамическом создании колонок таблиц значений, полей структур или свойств объектов разработчики часто используют цикл со счетчиком и формируют программные имена путем сложения базовой строки и числового индекса. Однако при код-ревью или статическом анализе кода можно встретить замечание: «При формировании идентификатора колонки выполняется неявное форматирование индекса». Разберем подробно, что означает это предупреждение, к какой критической ошибке оно приводит в рабочей системе и как правильно формировать машинные идентификаторы в 1С.
Рассмотрим типовой фрагмент кода, в котором возникает эта проблема:
ТЗвыборка = Новый ТаблицаЗначений;
ТЗвыборка.Колонки.Добавить("СправочникПоОсиУ", Новый ОписаниеТипов("СправочникСсылка.Справочник1"));
Для й = 0 По МассивВыборки.Количество() - 1 Цикл
ТЗвыборка.Колонки.Добавить("Колонка" + Строка(й), Новый ОписаниеТипов("Строка"), МассивВыборки[й].Наименование);
КонецЦикла;
Проанализируем механизм работы платформы 1С:Предприятие при преобразовании чисел в строки. Когда мы вызываем функцию Строка(Число) или выполняем неявное приведение типа при конкатенации вида "Колонка" + й, платформа использует стандартные региональные настройки локали информационной базы для пользовательского представления чисел.
Для русской локали числовые значения, начиная с 1 000 и более, форматируются с разделением групп разрядов. В качестве разделителя триад цифр платформа автоматически вставляет символ неразрывного пробела (Символы.НПП, код 160). В результате получаем следующее поведение:
й меньше 1000, строка формируется корректно: "Колонка0", "Колонка999"."Колонка" + Строка(й) возвращает строку "Колонка1 000" с неразрывным пробелом внутри.Колонки.Добавить() задает имя колонки, которое обязано быть валидным идентификатором встроенного языка 1С (начинаться с буквы или знака подчеркивания и не содержать пробелов, дефисов и спецсимволов)."Колонка1 000" программа аварийно завершает работу с исключением о недопустимом имени колонки.Именно поэтому использование функций пользовательского представления (Строка(), СокрЛП(), стандартной конкатенации) для формирования системных идентификаторов считается грубым нарушением стандартов разработки 1С.
Разберем основной стандартный метод решения задачи. Чтобы исключить добавление пробелов между разрядами числа, необходимо явно передать форматную строку с параметром ЧГ=0 (или ЧГ=), который отключает группировку:
Для й = 0 По МассивВыборки.Количество() - 1 Цикл
ИмяКолонки = "Колонка" + Формат(й, "ЧГ=0");
ТЗвыборка.Колонки.Добавить(ИмяКолонки, Новый ОписаниеТипов("Строка"), МассивВыборки[й].Наименование);
КонецЦикла;
Также удобно использовать функцию СтрШаблон, сохраняя форматирование числа без группировки:
Для й = 0 По МассивВыборки.Количество() - 1 Цикл
ИмяКолонки = СтрШаблон("Колонка%1", Формат(й, "ЧГ=0"));
ТЗвыборка.Колонки.Добавить(ИмяКолонки, Новый ОписаниеТипов("Строка"), МассивВыборки[й].Наименование);
КонецЦикла;
Посмотрим на наиболее производительный и лаконичный вариант. Функция платформы XMLСтрока() предназначена для преобразования примитивных типов данных в их каноническое строковое представление формата XML (XSD). Она никогда не добавляет региональные разделители групп разрядов и работает быстрее функции Формат().
Для й = 0 По МассивВыборки.Количество() - 1 Цикл
ИмяКолонки = "Колонка" + XMLСтрока(й);
ТЗвыборка.Колонки.Добавить(ИмяКолонки, Новый ОписаниеТипов("Строка"), МассивВыборки[й].Наименование);
КонецЦикла;
Рассмотрим альтернативный способ, который иногда встречается в коде, когда разработчики удаляют неразрывный пробел вручную:
Для й = 0 По МассивВыборки.Количество() - 1 Цикл
ИмяКолонки = "Колонка" + СтрЗаменить(Строка(й), Символы.НПП, "");
ТЗвыборка.Колонки.Добавить(ИмяКолонки, Новый ОписаниеТипов("Строка"), МассивВыборки[й].Наименование);
КонецЦикла;
Этот вариант является рабочим, однако он менее предпочтителен по сравнению с XMLСтрока() и Формат(), так как выполняет избыточные операции выделения памяти и поиска подстрок.
Сформулируем ключевые правила для безопасного формирования системных имен:
"Имя" + Число или вызов Строка(Число) для генерации имен системных объектов.XMLСтрока().