Почему в таблице значений 1С строки заполняются с пробелами и как это исправить?

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

При разработке в 1С:Предприятие часто возникает ситуация: мы выгружаем данные из запроса в таблицу значений, пытаемся обработать строковые поля (например, коды справочников), но в конце значений мистическим образом появляются пробелы. Разберем типичную проблему: почему функции СокрЛП и СтрЗаменить не помогают, и как правильно настроить типы данных для корректной работы поиска и фильтрации.

Анализ проблемы: откуда берутся лишние пробелы?

Представим стандартную задачу. Мы получаем данные о товарах из документа и добавляем их в заранее созданную или скопированную таблицу значений. Посмотрим на код, который часто пишут в подобных случаях:


НоваяСтрока = ТаблицаСКодамиНоменклатуры.Добавить(); 
НоваяСтрока.КодНоменклатуры = СокрЛП(СтрокаРезультата.КодНоменклатуры);

Несмотря на использование функции очистки, если после этого мы попытаемся найти строку по значению "000051", поиск не даст результатов, так как в ячейке фактически хранится значение "000051 " (с пробелами на конце). Почему так происходит?

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

  1. Строка переменной длины — хранит ровно столько символов, сколько мы в нее передали (с ограничением по максимуму).
  2. Строка фиксированной длины — всегда дополняет короткие значения пробелами справа до максимального заданного размера.

Именно из-за второго пункта наши попытки очистить строку не приносят результата. Сама функция СокрЛП() отрабатывает корректно и удаляет пробелы. Но в момент присвоения результата в колонку таблицы значений (НоваяСтрока.КодНоменклатуры = ...), платформа 1С мгновенно возвращает недостающие пробелы обратно в соответствии с жестким типом данных (строка фиксированной длины).

Как правило, колонки с кодами справочников (например, номенклатуры) наследуют свой тип от самого реквизита в конфигураторе. Системный реквизит Код у справочника часто имеет фиксированную длину.

Решение 1: Правильное создание таблицы значений

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


КвалификаторСтроки = Новый КвалификаторыСтроки(0); // 0 означает неограниченную (переменную) длину
МассивСтрок = Новый Массив; 
МассивСтрок.Добавить(Тип("Строка")); 
ОписаниеТиповСтрок = Новый ОписаниеТипов(МассивСтрок, , КвалификаторСтроки); 

ТаблицаРезультатаЗапроса = Новый ТаблицаЗначений; 
ТаблицаРезультатаЗапроса.Колонки.Добавить("КодНоменклатуры", ОписаниеТиповСтрок);

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

Решение 2: Приведение типа непосредственно в запросе

Если данные попадают в таблицу значений через метод результата запроса Выгрузить(), таблица автоматически унаследует типы полей из базы данных. Избежать этого можно, изменив тип данных еще на этапе SQL-запроса 1С.

Рассмотрим, как использовать функцию ВЫРАЗИТЬ в тексте запроса:


Запрос = Новый Запрос; 
Запрос.Текст = 
    "ВЫБРАТЬ 
    | Товары.Ссылка.Номер КАК Номер, 
    | Товары.Количество КАК Количество, 
    | ВЫРАЗИТЬ(Товары.Номенклатура.Код КАК СТРОКА(50)) КАК КодНоменклатуры, 
    | Товары.Дата КАК Дата 
    |ИЗ 
    | Документ.РеализацияТоваровУслуг.Товары КАК Товары";

При использовании конструкции ВЫРАЗИТЬ(... КАК СТРОКА(X)), результатом всегда будет являться строка переменной длины. При последующей выгрузке в таблицу значений проблема с лишними пробелами исчезнет сама собой.

Разбор "костылей" и необычных ситуаций

Часто в поисках решения программисты случайно находят обходные пути. Рассмотрим один из таких подходов, когда данные сначала помещались в массив:


МассивКодов = Новый Массив; 
Для Каждого Строка Из ТаблицаРезультатаЗапроса Цикл 
    МассивКодов.Добавить(СокрЛП(СтрЗаменить(Строка.КодНоменклатуры, Символы.НПП, ""))); 
    НоваяСтрока = ТаблицаСКодамиНоменклатуры.Добавить(); 
    НоваяСтрока.КодНоменклатуры = МассивКодов[0]; 
КонецЦикла;

Почему этот код временно решал проблему? Дело в том, что коллекции типа Массив не имеют жесткого ограничения типов элементов. Очищенная от пробелов строка помещалась в массив как строка переменной длины, а затем (если таблица-приемник имела составной тип или тип "Произвольный") ложилась туда без дополнения пробелами. Тем не менее, это архитектурно неверный подход, который приводит к запутанности кода и ошибкам при рефакторинге.

Дополнительно: очистка спецсимволов и неразрывных пробелов

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

В современных версиях платформы (начиная с 8.3.23) мы можем использовать объект РегулярноеВыражение, чтобы в одну строку вычистить все пустые символы без десятков вложенных СтрЗаменить:


Регулярка = Новый РегулярноеВыражение("\s");
Регулярка.ГлобальныйПоиск = Истина;
ЧистыйКод = Регулярка.Заменить(ИсходныйКод, "");

Используя правильное приведение типов в запросе или корректную настройку квалификаторов строк, мы полностью исключаем проблему появления лишних пробелов и обеспечиваем безошибочный поиск строк в таблицах значений.

← На главную