Как добавить значения из массива в ТаблицуЗначений 1С в качестве колонок и избежать ошибки "Неверное имя колонки"?

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

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

Понимание причины ошибки "Неверное имя колонки"

Когда мы пытаемся добавить колонку в ТаблицуЗначений, используя метод Колонки.Добавить(), 1С предъявляет строгие требования к имени этой колонки. Имя колонки должно соответствовать правилам именования идентификаторов в языке 1С, что означает:

  1. Оно может содержать только алфавитные символы, цифры и знак подчеркивания.
  2. Оно не может начинаться с цифры.
  3. Пробелы, точки, запятые, дефисы и другие специальные символы недопустимы.

В нашем случае, когда мы получаем значения из массива, эти значения могут быть произвольными строками, например, " Наименование элемента ", "2-ой Показатель", "Количество (шт.)". Даже после использования функции СокрЛП(), которая убирает пробелы в начале и конце строки, внутри строки могут остаться недопустимые символы, или строка может начинаться с цифры, что приведет к ошибке.

Давайте посмотрим на пример кода, который вызывает ошибку:


ТЗ1 = Новый ТаблицаЗначений;
Массив1 = СтрРазделить(РеквизитТаблицы,",",Ложь); // Пример: РеквизитТаблицы = " Наименование1 ,Количество (шт.), 2 Показатель"

Для Индекс = 0 По Массив1.ВГраница Цикл
    стр = СокрЛП(Массив1[Индекс]); // Убираем начальные/конечные пробелы
    Попытка
        ТЗ1.Колонки.Добавить(стр); // Здесь может возникнуть ошибка
    Исключение
        Сообщить("Ошибка при добавлении колонки '" + стр + "': " + ОписаниеОшибки());
    КонецПопытки;
КонецЦикла;

В этом примере, если стр примет значение, например, "Количество (шт.)" или "2 Показатель", 1С выдаст ошибку "Неверное имя колонки", потому что скобки, пробелы внутри строки и начальная цифра не соответствуют правилам.

Решение 1: Использование служебных имен колонок и заголовков

Это один из самых надежных и рекомендуемых способов обработки динамических имен колонок. Мы создаем колонки со служебными, заведомо корректными именами (например, "Колонка1", "Колонка2", "Данные_XXX"), а исходное значение из массива, которое может содержать любые символы, присваиваем свойству Заголовок у созданной колонки. Свойство Заголовок предназначено для отображения пользователю и не имеет таких строгих ограничений на символы.

Рассмотрим по шагам, как реализовать этот подход:

  1. Генерируем служебное имя колонки. Для этого мы можем использовать простой счетчик или комбинацию префикса и уникального идентификатора.
  2. Создаем колонку с этим служебным именем.
  3. Присваиваем исходное значение из массива свойству Заголовок созданной колонки.
  4. Сохраняем соответствие между исходным значением из массива и служебным именем колонки. Это понадобится нам в дальнейшем для доступа к данным, когда мы будем знать только исходное имя.

Посмотрим на пример кода:


ТЗ1 = Новый ТаблицаЗначений;
Массив1 = СтрРазделить(РеквизитТаблицы,",",Ложь); // Пример: " Наименование1 ,Количество (шт.), 2 Показатель"

// Создаем Соответствие для хранения маппинга: ИсходноеНазвание -> СлужебноеИмяКолонки
СоответствиеИменКолонок = Новый Соответствие;

ИндексКолонки = 1;
Для Каждого СтрокаМассива Из Массив1 Цикл
    ОригинальноеИмя = СокрЛП(СтрокаМассива);
    
    // Генерируем служебное имя, которое гарантированно будет корректным
    СлужебноеИмяКолонки = "Колонка_" + ИндексКолонки;
    
    // Добавляем колонку
    НоваяКолонка = ТЗ1.Колонки.Добавить(СлужебноеИмяКолонки);
    
    // Присваиваем оригинальное имя в Заголовок
    НоваяКолонка.Заголовок = ОригинальноеИмя;
    
    // Опционально: устанавливаем тип данных для колонки
    // Если тип не указан, колонка будет иметь неопределенный тип
    НоваяКолонка.Тип = Новый ОписаниеТипов("Строка"); 
    
    // Сохраняем соответствие
    СоответствиеИменКолонок.Вставить(ОригинальноеИмя, СлужебноеИмяКолонки);
    ИндексКолонки = ИндексКолонки + 1;
КонецЦикла;

// Теперь мы можем добавлять строки и заполнять данные
// Например, если у нас есть данные для "Количество (шт.)"
НоваяСтрока = ТЗ1.Добавить();
// Получаем служебное имя для "Количество (шт.)"
СлужебноеИмяДляКоличества = СоответствиеИменКолонок.Получить("Количество (шт.)");
Если СлужебноеИмяДляКоличества <> Неопределено Тогда
    НоваяСтрока[СлужебноеИмяДляКоличества] = 123;
КонецЕсли;

// Для отображения пользователю ТЗ будет выглядеть с заголовками "Наименование1", "Количество (шт.)" и т.д.
// А для программного доступа мы используем СлужебноеИмяКолонки.

// Отладка:
Сообщить("Структура ТЗ:");
Для Каждого Кол Из ТЗ1.Колонки Цикл
    Сообщить("Имя: " + Кол.Имя + ", Заголовок: " + Кол.Заголовок + ", Тип: " + Кол.Тип);
КонецЦикла;

Этот подход гарантирует работоспособность в любых условиях, независимо от содержимого исходных строк. Единственное "усложнение" – это необходимость использовать Соответствие для маппинга и обращаться к колонкам по служебным именам. Однако это повышает надежность и стабильность кода.

Решение 2: Преобразование строки в допустимое имя

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

Рассмотрим логику такого преобразования:

  1. Удаляем начальные и конечные пробелы с помощью СокрЛП().
  2. Заменяем все недопустимые символы (пробелы внутри строки, скобки, дефисы, точки и т.д.) на допустимые, например, на знак подчеркивания _.
  3. Проверяем, не начинается ли преобразованная строка с цифры. Если да, добавляем префикс, например, "Колонка_".
  4. Убеждаемся, что получившееся имя не пустое. Если пустое, генерируем стандартное имя (например, "ПустаяКолонка_N").

В Библиотеке стандартных подсистем (БСП) есть функция ПреобразоватьСтрокуВДопустимоеНаименованиеКолонки, которая реализует подобную логику. Если у нас нет доступа к БСП или требуется специфичная логика, мы можем создать свою функцию:


// Функция для преобразования строки в допустимое имя колонки
Функция ПолучитьДопустимоеИмяКолонки(ИсходнаяСтрока) Экспорт
    ИмяКолонки = СокрЛП(ИсходнаяСтрока);
    
    // Заменяем все недопустимые символы на '_'
    // Можно перечислить символы, которые хотим заменить
    ИмяКолонки = СтрЗаменить(ИмяКолонки, " ", "_");
    ИмяКолонки = СтрЗаменить(ИмяКолонки, "(", "_");
    ИмяКолонки = СтрЗаменить(ИмяКолонки, ")", "_");
    ИмяКолонки = СтрЗаменить(ИмяКолонки, "-", "_");
    ИмяКолонки = СтрЗаменить(ИмяКолонки, ".", "_");
    ИмяКолонки = СтрЗаменить(ИмяКолонки, ",", "_");
    ИмяКолонки = СтрЗаменить(ИмяКолонки, "/", "_");
    ИмяКолонки = СтрЗаменить(ИмяКолонки, "\", "_");
    // Добавьте другие символы по необходимости
    
    // Удаляем повторяющиеся подчеркивания (опционально, для читаемости)
    Пока Найти(ИмяКолонки, "__") > 0 Цикл
        ИмяКолонки = СтрЗаменить(ИмяКолонки, "__", "_");
    КонецЦикла;
    
    // Проверяем, не начинается ли имя с цифры
    Если Лев(ИмяКолонки, 1) = "0" ИЛИ Лев(ИмяКолонки, 1) = "1" ИЛИ 
       Лев(ИмяКолонки, 1) = "2" ИЛИ Лев(ИмяКолонки, 1) = "3" ИЛИ 
       Лев(ИмяКолонки, 1) = "4" ИЛИ Лев(ИмяКолонки, 1) = "5" ИЛИ 
       Лев(ИмяКолонки, 1) = "6" ИЛИ Лев(ИмяКолонки, 1) = "7" ИЛИ 
       Лев(ИмяКолонки, 1) = "8" ИЛИ Лев(ИмяКолонки, 1) = "9" Тогда
        ИмяКолонки = "Колонка_" + ИмяКолонки;
    КонецЕсли;
    
    // Если имя стало пустым или слишком коротким после преобразований
    Если СтрДлина(ИмяКолонки) = 0 Тогда
        ИмяКолонки = "ПустаяКолонка"; // Или генерируем уникальное имя
    КонецЕсли;
    
    Возврат ИмяКолонки;
КонецФункции;

ТЗ1 = Новый ТаблицаЗначений;
Массив1 = СтрРазделить(РеквизитТаблицы,",",Ложь); // Пример: " Наименование1 ,Количество (шт.), 2 Показатель"

Для Каждого СтрокаМассива Из Массив1 Цикл
    ОригинальноеИмя = СокрЛП(СтрокаМассива);
    ДопустимоеИмя = ПолучитьДопустимоеИмяКолонки(ОригинальноеИмя);
    
    Попытка
        ТЗ1.Колонки.Добавить(ДопустимоеИмя);
    Исключение
        Сообщить("Ошибка при добавлении колонки '" + ДопустимоеИмя + "' (оригинал: '" + ОригинальноеИмя + "'): " + ОписаниеОшибки());
    КонецПопытки;
КонецЦикла;

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

Решение 3: Использование альтернативных структур данных для динамических данных

В некоторых случаях, когда нам нужно хранить очень динамичные данные, и жесткое именование колонок по каждому элементу массива вызывает сложности, стоит рассмотреть альтернативные структуры данных. Объект ТаблицаЗначений отлично подходит для табличных данных с предопределенным или предсказуемым набором колонок. Однако для более свободных структур могут быть более подходящие варианты.

  1. Массив структур: Если каждый элемент массива представляет собой набор ключ-значение, мы можем создать Массив, где каждый элемент массива будет Структурой. Ключи структуры будут выступать в роли "имен колонок", а их значения – это данные. Этот подход особенно удобен, если количество и имена "колонок" могут сильно варьироваться для каждой "строки".
    
    МассивДанных = Новый Массив;
    
    // Первая "строка" данных
    СтруктураДанных1 = Новый Структура;
    СтруктураДанных1.Вставить("НаименованиеТовара", "Монитор");
    СтруктураДанных1.Вставить("Цена", 15000);
    МассивДанных.Добавить(СтруктураДанных1);
    
    // Вторая "строка" данных с другим набором полей
    СтруктураДанных2 = Новый Структура;
    СтруктураДанных2.Вставить("Код", "00123");
    СтруктураДанных2.Вставить("КоличествоНаСкладе", 100);
    СтруктураДанных2.Вставить("Поставщик", "Рога и Копыта");
    МассивДанных.Добавить(СтруктураДанных2);
    
    // Обработка данных
    Для Каждого ДанныеСтроки Из МассивДанных Цикл
        Если ДанныеСтроки.Свойство("НаименованиеТовара") Тогда
            Сообщить("Товар: " + ДанныеСтроки.НаименованиеТовара);
        КонецЕсли;
        Если ДанныеСтроки.Свойство("КоличествоНаСкладе") Тогда
            Сообщить("На складе: " + ДанныеСтроки.КоличествоНаСкладе);
        КонецЕсли;
    КонецЦикла;
    
  2. Таблица значений с фиксированным набором колонок и дополнительной колонкой для "динамического" содержимого: Мы можем создать ТаблицуЗначений с предопределенными колонками, например, "Показатель" и "Значение". Каждая строка такой таблицы будет представлять собой отдельный "показатель" с его значением. Этот подход известен как "сворачивание" или "транспонирование" данных.
    
    ТЗПоказателей = Новый ТаблицаЗначений;
    ТЗПоказателей.Колонки.Добавить("Показатель", Новый ОписаниеТипов("Строка"));
    ТЗПоказателей.Колонки.Добавить("Значение", Новый ОписаниеТипов("Число"));
    
    // Добавляем данные
    НоваяСтрока = ТЗПоказателей.Добавить();
    НоваяСтрока.Показатель = "Наименование элемента";
    НоваяСтрока.Значение = "Какой-то текст"; // Здесь может быть любое значение, в зависимости от типа колонки
    
    НоваяСтрока = ТЗПоказателей.Добавить();
    НоваяСтрока.Показатель = "Количество (шт.)";
    НоваяСтрока.Значение = 150;
    
    НоваяСтрока = ТЗПоказателей.Добавить();
    НоваяСтрока.Показатель = "2 Показатель";
    НоваяСтрока.Значение = 25.5;
    
    // Обработка данных
    Для Каждого СтрокаТЗ Из ТЗПоказателей Цикл
        Сообщить("Показатель: " + СтрокаТЗ.Показатель + ", Значение: " + СтрокаТЗ.Значение);
    КонецЦикла;
    

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

Важные нюансы и отладка

При работе с динамическим созданием колонок в ТаблицеЗначений, особенно полезно учитывать следующие моменты:

  1. Тип данных колонки: Всегда рекомендуется указывать тип данных для новой колонки с помощью Новый ОписаниеТипов(). Это повышает надежность кода и предотвращает потенциальные ошибки при дальнейшей работе с данными. Если тип не указан, по умолчанию колонка будет иметь неопределенный тип, что позволит хранить в ней значения любого типа, но может привести к проблемам с сортировкой или фильтрацией.
    
    НоваяКолонка = ТЗ1.Колонки.Добавить("МояКолонка");
    НоваяКолонка.Тип = Новый ОписаниеТипов("Строка"); // Указываем тип Строка
    // Или для числа:
    // НоваяКолонка.Тип = Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(10, 2));
    
  2. Объект ТаблицаЗначений: Помним, что ТаблицаЗначений – это динамический объект, который хранится в оперативной памяти и существует только во время выполнения программного кода. Для сохранения данных в базу данных необходимо использовать другие объекты, такие как табличные части документов, справочников или регистры.
  3. Отладка: Если вы столкнулись с ошибкой "Неверное имя колонки", всегда ставьте точку останова на строке ТЗ.Колонки.Добавить(ИмяКолонки). В режиме отладчика внимательно проверьте содержимое переменной ИмяКолонки (в нашем случае стр или ДопустимоеИмя). Это поможет точно определить, какое именно значение вызывает ошибку и какие недопустимые символы в нем содержатся. Часто бывает, что кроме пробелов, есть другие неочевидные символы, например, символы новой строки или табуляции.
    
    // ...
    стр = СокрЛП(Массив1[Индекс]); 
    // Установите здесь точку останова и посмотрите значение переменной "стр"
    ТЗ1.Колонки.Добавить(стр); 
    // ...
    

    Даже если СокрЛП() используется, мы должны убедиться, что проблема не в других внутренних символах. Внимательный анализ значения переменной в отладчике – ключ к пониманию истинной причины ошибки.

Принимая во внимание эти подходы и рекомендации, мы сможем эффективно и надежно работать с динамическим добавлением колонок в ТаблицуЗначений в 1С, избегая распространенных ошибок и создавая более гибкие и устойчивые решения.

← На главную