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