Как разобрать строку по разделителю и загрузить данные в справочник в 1С

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

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

Способ 1. Использование встроенной функции СтрРазделить (начиная с платформы 8.3)

Если разработка ведется на актуальных релизах платформы «1С:Предприятие 8.3», наиболее удобным и быстродействующим решением является штатная функция СтрРазделить(). Она принимает исходный текст, символ-разделитель и флаг включения пустых строк, возвращая готовый массив подстрок.

Рассмотрим пример использования:


ИсхСтрока = "#2#LAKISHA TOMBLIN#06.08.1961#F#2#Administrative Clerk#Provides administrative suppo#Hourly#$#l_tomblin@nnl.com# Total #Hourly Staff";
МассивПолей = СтрРазделить(ИсхСтрока, "#", Истина);

// Обратите внимание: так как строка начинается с символа "#",
// первым элементом массива (с индексом 0) будет пустая строка.
КодЭлемента = МассивПолей[1];
НаименованиеЭлемента = МассивПолей[2];

Способ 2. Трюк со СтрЗаменить и СтрПолучитьСтроку (для платформы 8.2)

В платформе 1С 8.2 функции СтрРазделить() еще не существовало. Классический и самый компактный способ разбора без привлечения внешних библиотек заключается в подмене символа-разделителя на символ перевода строки Символы.ПС с последующим построчным чтением через СтрПолучитьСтроку().

Проанализируем пример реализации данного подхода:


ИсхСтрока = "#2#LAKISHA TOMBLIN#06.08.1961#F#2#Administrative Clerk#Provides administrative suppo#Hourly#$#l_tomblin@nnl.com# Total #Hourly Staff";

// Заменяем разделитель на символ перевода строки
мСтрока = СтрЗаменить(ИсхСтрока, "#", Символы.ПС);

// Нумерация строк в СтрПолучитьСтроку начинается с 1.
// Так как перед первой решеткой ничего нет, 1-я строка будет пустой.
Код = СтрПолучитьСтроку(мСтрока, 2);
ФИО = СтрПолучитьСтроку(мСтрока, 3);
ДатаРождения = СтрПолучитьСтроку(мСтрока, 4);

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

Способ 3. Использование функции из Библиотеки Стандартных Подсистем (БСП)

Если конфигурация разработана на базе БСП (или типовых конфигураций 1С), в общем модуле ОбщегоНазначения или СтроковыеФункцииКлиентСервер доступна готовая процедура разложения строки в массив. Этот вариант полностью совместим с 1С 8.2 и возвращает стандартный массив элементов.


// В типовых конфигурациях на базе БСП
МассивДанных = ОбщегоНазначенияКлиентСервер.РазложитьСтрокуВМассивПодстрок(ИсхСтрока, "#");

// Либо в более старых редакциях БСП:
// МассивДанных = ОбщегоНазначения.РазложитьСтрокуВМассивПодстрок(ИсхСтрока, "#");

Способ 4. Универсальный циклический разбор через Найти и Сред

Если в базе нет БСП, а использовать подмену на Символы.ПС нежелательно из-за риска встретить переводы строк в тексте, разберем по шагам создание собственной универсальной функции разбора. Реализуем функцию, которая находит позиции разделителя и последовательно отсекает фрагменты:


Функция РазложитьСтрокуВМассив(Знач ИсходныйТекст, Знач Разделитель) Экспорт
    Результат = Новый Массив;
    ДлинаРазделителя = СтрДлина(Разделитель);
    
    Позиция = Найти(ИсходныйТекст, Разделитель);
    Пока Позиция > 0 Цикл
        Подстрока = Лев(ИсходныйТекст, Позиция - 1);
        Результат.Добавить(Подстрока);
        ИсходныйТекст = Сред(ИсходныйТекст, Позиция + ДлинаРазделителя);
        Позиция = Найти(ИсходныйТекст, Разделитель);
    КонецЦикла;
    
    Результат.Добавить(ИсходныйТекст);
    Возврат Результат;
КонецФункции

Подводные камни и преобразование типов данных

После того как строка разобрана на составляющие, важно корректно подготовить значения для записи в реквизиты справочника. Выделим основные нюансы:

  1. Ведущий разделитель: В строках вида #2#LAKISHA... первый символ — это разделитель. Это означает, что первый полученный элемент будет пустой строкой. Нужные данные начинаются со следующего индекса.
  2. Преобразование даты: В текстовых выгрузках дата часто представлена в человекочитаемом виде 06.08.1961 (ДД.ММ.ГГГГ). Конструктор Дата("06.08.1961") в 1С вызовет синтаксическую ошибку времени выполнения, так как требует строковый формат ГГГГММДД. Дату необходимо преобразовывать вручную:
    
    СтрД = "06.08.1961";
    // Формируем формат ГГГГММДД: "1961" + "08" + "06"
    ДатаРождения = Дата(Сред(СтрД, 7, 4) + Сред(СтрД, 4, 2) + Сред(СтрД, 1, 2));
    
  3. Преобразование чисел: Если в строке присутствуют символы валют (например, $) или пробелы, перед приведением к типу Число() их необходимо убрать через СтрЗаменить().

Итоговый пример комплексной загрузки файла в справочник

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


Процедура ЗагрузитьДанныеИзФайла(ПутьКФайлу)
    ФайлТекст = Новый ЧтениеТекста(ПутьКФайлу, КодировкаТекста.ANSI);
    Строка = ФайлТекст.ПрочитатьСтроку();
    
    НачатьТранзакцию();
    Попытка
        Пока Строка <> Неопределено Цикл
            Если Не ПустаяСтрока(Строка) Тогда
                Подстроки = СтрЗаменить(Строка, "#", Символы.ПС);
                
                // Пропускаем первый пустой элемент перед начальным знаком "#"
                КодЭл          = СокрЛП(СтрПолучитьСтроку(Подстроки, 2));
                ИмяЭл          = СокрЛП(СтрПолучитьСтроку(Подстроки, 3));
                ДатаРожденияСтр = СокрЛП(СтрПолучитьСтроку(Подстроки, 4));
                
                // Проверяем наличие элемента в базе во избежание дублирования
                Спр = Справочники.БСК.НайтиПоКоду(КодЭл);
                Если Спр.Пустая() Тогда
                    СпрОбъект = Справочники.БСК.СоздатьЭлемент();
                    СпрОбъект.Код = КодЭл;
                Иначе
                    СпрОбъект = Спр.ПолучитьОбъект();
                КонецЕсли;
                
                СпрОбъект.Наименование = ИмяЭл;
                
                // Преобразуем дату из формата ДД.ММ.ГГГГ
                Если СтрДлина(ДатаРожденияСтр) = 10 Тогда
                    СпрОбъект.DateOfBirth = Дата(Сред(ДатаРожденияСтр, 7, 4) + Сред(ДатаРожденияСтр, 4, 2) + Сред(ДатаРожденияСтр, 1, 2));
                КонецЕсли;
                
                // Отключаем лишние платформенные проверки для ускорения загрузки
                СпрОбъект.ОбменДанными.Загрузка = Истина;
                СпрОбъект.Записать();
            КонецЕсли;
            
            Строка = ФайлТекст.ПрочитатьСтроку();
        КонецЦикла;
        
        ЗафиксироватьТранзакцию();
        Сообщить("Загрузка успешно завершена!");
    Исключение
        ОтменитьТранзакцию();
        ВызватьИсключение "Ошибка при загрузке данных: " + ОписаниеОшибки();
    КонецПопытки;
    
    ФайлТекст.Закрыть();
КонецПроцедуры

Использование потокового объекта ЧтениеТекста вместо загрузки всего документа целиком бережет оперативную память, а явное управление транзакциями существенно повышает скорость записи большого количества элементов.

← На главную