Как правильно создать структуру из двух массивов в 1С и избежать ошибок в именах ключей?

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

При разработке на платформе 1С:Предприятие 8.3 часто возникает задача преобразования данных из плоских списков или колонок таблицы в коллекцию типа "ключ-значение". На первый взгляд, использование объекта Структура кажется идеальным решением. Однако начинающие разработчики часто сталкиваются с системной ошибкой: "Задано неправильное имя атрибута структуры". Рассмотрим подробнее, почему это происходит, и как правильно реализовать заполнение структуры на основе массивов.

Разберем причину возникновения ошибки

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

Когда мы пытаемся выполнить код Структура.Вставить(Строка(Массив1[Индекс]), Массив2[Индекс]), где в первом массиве хранятся годы (например, 2022), функция Строка() преобразует число по умолчанию с использованием региональных настроек. В результате число "2022" превращается в строку "2 022" (с неразрывным пробелом в качестве разделителя разрядов). Пробел является недопустимым символом для ключа структуры, что и вызывает ошибку.

Решение №1: Использование функции Формат для очистки строк

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


// Выгружаем данные из таблицы значений
Массив1 = Табл.ВыгрузитьКолонку("Год");
Массив2 = Табл.ВыгрузитьКолонку("Выходной");

СтруктураВыходные = Новый Структура();

Для Индекс = 0 По Массив1.Количество() - 1 Цикл 
    // Используем параметр "ЧГ=0", чтобы убрать группировку разрядов
    КлючСтр = Формат(Массив1[Индекс], "ЧГ=0");
    
    // Добавляем префикс, так как ключ не может начинаться с цифры
    КлючСтр = "Год_" + КлючСтр;
    
    СтруктураВыходные.Вставить(КлючСтр, Массив2[Индекс]);
КонецЦикла;

В данном примере мы применили Формат(Значение, "ЧГ=0"). Параметр ЧГ=0 (Число: Группировка = 0) гарантирует, что в строке не будет лишних пробелов, независимо от настроек сервера или операционной системы.

Решение №2: Использование объекта Соответствие

Если нам критически важно использовать именно числовые значения в качестве ключей (без префиксов типа "Год_") или если ключи могут содержать любые символы, нам следует рассмотреть объект Соответствие. Проанализируем ситуацию: в отличие от структуры, Соответствие позволяет использовать в качестве ключа значение любого типа.


Массив1 = Табл.ВыгрузитьКолонку("Год");
Массив2 = Табл.ВыгрузитьКолонку("Выходной");

// Создаем Соответствие вместо Структуры
ДанныеВыходных = Новый Соответствие();

Для Индекс = 0 По Массив1.Количество() - 1 Цикл 
    // Ключом будет само Число (год), преобразование в строку не требуется
    ДанныеВыходных.Вставить(Массив1[Индекс], Массив2[Индекс]);
КонецЦикла;

// Получение значения также просто:
ВыходныеВ2022 = ДанныеВыходных.Получить(2022);

Важный момент: к свойствам Структуры можно обращаться через точку (Структура.ИмяКлюча), а к элементам Соответствия — только через метод Получить(Ключ) или через квадратные скобки. Если вы работаете с динамическими данными, Соответствие часто оказывается более гибким инструментом.

Борьба с неразрывными пробелами (Символы.НПП)

Иногда данные приходят уже в виде строк, содержащих скрытые символы. Выясним причину, почему обычный метод СтрЗаменить(Строка, " ", "") может не помочь. В 1С разделителем разрядов часто выступает не обычный пробел (код 32), а неразрывный пробел (код 160). Чтобы гарантированно очистить строку, используйте конструкцию:


// Очистка строки от неразрывных пробелов
ЧистаяСтрока = СтрЗаменить(СтрокаСПробелом, Символы.НПП, "");
// Дополнительно убираем обычные пробелы
ЧистаяСтрока = СтрЗаменить(ЧистаяСтрока, " ", "");

Это позволит подготовить строку к использованию в качестве идентификатора ключа, если вы всё же решили использовать Структуру.

Рекомендации по архитектуре кода

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

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


СтруктураВыходные = Новый Структура();

Для Каждого СтрокаТЗ Из Табл Цикл
    // Сразу формируем правильный ключ из строки таблицы
    Ключ = "Год" + Формат(СтрокаТЗ.Год, "ЧГ=0");
    СтруктураВыходные.Вставить(Ключ, СтрокаТЗ.Выходной);
КонецЦикла;

Этот подход экономит память (мы не дублируем данные в массивах) и гарантирует, что год и количество выходных будут взяты из одной и той же строки таблицы.

Итоги

Подведем итоги нашего разбора:

  1. Структура требует, чтобы ключи были валидными идентификаторами (без пробелов, не с цифры).
  2. Функция Строка() для чисел часто добавляет пробелы — используйте Формат(Число, "ЧГ=0").
  3. Если ключи непредсказуемы или должны быть числами/датами, используйте Соответствие.
  4. Всегда проверяйте наличие неразрывных пробелов (Символы.НПП) при обработке строковых данных.

Выбирайте подходящий тип коллекции в зависимости от ваших задач, и ваш код будет работать стабильно и без ошибок!

← На главную