Часто в практике разработчика 1С возникает ситуация, когда пользователи предоставляют данные в формате Excel, где вместо прямых ссылок на объекты содержатся лишь их текстовые представления, например: "Заказ клиента 1111111 от 15.01.2021 23:59:59". Наша задача — корректно преобразовать эту строку в полноценную ссылку на документ в базе данных 1С для дальнейшей обработки. Рассмотрим подробно, как это сделать, разберем возможные "подводные камни" и выберем наиболее эффективные методы.
Если мы имеем дело со стандартным представлением документа, строка состоит из трех ключевых частей: типа документа, его номера и даты. Разберем алгоритм, при котором мы программно "разрезаем" строку на составляющие.
Для начала проанализируем структуру строки. Мы знаем, что дата обычно находится в конце и имеет фиксированную длину (19 символов для формата "ДД.ММ.ГГГГ ЧЧ:ММ:СС"). Рассмотрим пример кода, который позволяет извлечь данные:
Представление = "Заказ клиента 1111111 от 15.01.2021 23:59:59";
// Извлекаем дату из последних 19 символов
СтрокаДаты = Прав(Представление, 19);
ДатаДокумента = Дата(СтрЗаменить(СтрокаДаты, ".", "")); // Приводим к типу Дата
// Отсекаем дату и слово " от ", чтобы найти номер
ОстатокСтроки = Лев(Представление, СтрДлина(Представление) - 22);
ЧастиСтроки = СтрРазделить(ОстатокСтроки, " ");
НомерДокумента = ЧастиСтроки[ЧастиСтроки.ВГраница()]; // Номер обычно последнее слово перед "от"
После получения номера и даты мы можем использовать метод НайтиПоНомеру. Важно помнить, что в 1С номер документа уникален только в пределах периода (года), поэтому передача даты обязательна:
Ссылка = Документы.ЗаказКлиента.НайтиПоНомеру(НомерДокумента, ДатаДокумента);
Если Ссылка.Пустая() Тогда
Сообщить("Документ не найден!");
КонецЕсли;
Метод ручного разбиения строки может "сломаться", если формат номера изменится или в названии документа появятся лишние пробелы. Более надежным способом является использование регулярных выражений. Начиная с версии платформы 8.3.23, регулярные выражения доступны "из коробки", но для более старых версий можно использовать COMОбъект("VBScript.RegExp").
Рассмотрим, как с помощью паттерна выделить номер и дату. Паттерн (.*)\s(.+)\sот\s(\d{2}.\d{2}.\d{4}.*) позволит нам гибко разобрать строку, где:
Проанализируем пример функции для платформы 8.3.23+:
Результат = СтрНайтиПоРегулярномуВыражению(СтрокаИзExcel, "(\d+)\sот\s(\d{2}.\d{2}.\d{4})");
// Это позволит быстро вычленить нужные подстроки даже в нестандартных текстах.
Одной из главных ошибок при загрузке данных из Excel является выполнение поиска ссылки в цикле. Если в файле 10 000 строк, система выполнит 10 000 отдельных запросов к базе данных, что крайне медленно. Выясним, как сделать это правильно с помощью запроса.
Рациональнее всего сначала загрузить все данные из Excel в ТаблицуЗначений, подготовить в ней колонки "Номер" и "Дата", а затем передать эту таблицу в запрос:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВТ_ДанныеExcel.Номер КАК Номер,
| ВТ_ДанныеExcel.Дата КАК Дата
|ПОМЕСТИТЬ ВТ_Excel
|ИЗ
| &ТЗ_Excel КАК ВТ_ДанныеExcel
|;
|ВЫБРАТЬ
| Заказ.Ссылка,
| ВТ_Excel.Номер
|ИЗ
| ВТ_Excel КАК ВТ_Excel
| ЛЕВОЕ СОЕДИНЕНИЕ Документ.ЗаказКлиента КАК Заказ
| ПО ВТ_Excel.Номер = Заказ.Номер
| И ВТ_Excel.Дата = Заказ.Дата";
Запрос.УстановитьПараметр("ТЗ_Excel", ВашаТаблицаЗначений);
РезультатЗапроса = Запрос.Выполнить().Выгрузить();
Этот подход позволяет найти все ссылки одним обращением к серверу БД, что ускоряет загрузку в десятки раз.
Проанализируем ситуацию: если вы сами формируете отчет, который пользователи потом редактируют в Excel, всегда добавляйте скрытую колонку с Уникальным Идентификатором (GUID). Это исключит любые проблемы с поиском.
В Excel это будет выглядеть как строка вида "550e8400-e29b-41d4-a716-446655440000". При загрузке нам не нужно ничего парсить и искать по номеру:
// Превращаем строку GUID обратно в ссылку
Идентификатор = Новый УникальныйИдентификатор(СтрокаИзExcel);
Ссылка = Документы.ЗаказКлиента.ПолучитьСсылку(Идентификатор);
Важный момент: метод ПолучитьСсылку не обращается к базе данных. Он создает ссылку "в памяти". Чтобы проверить, существует ли такой документ на самом деле, используйте Ссылка.ПолучитьОбъект() = Неопределено или проверьте наличие ссылки в запросе.
ОбщегоНазначения.ДополнитьСтрокуЛП() (если используете БСП) или просто кодом:
Пока СтрДлина(НомерИзExcel) < 11 Цикл
НомерИзExcel = "0" + НомерИзExcel;
КонецЦикла;
НайтиПоНомеру учитывает префиксы автоматически, а вот в запросе при соединении таблиц нужно быть внимательным и сопоставлять номера в том виде, в котором они хранятся в БД.Подводя итог, скажем: если есть возможность повлиять на формат выгрузки — используйте GUID. Если данные уже даны в виде строки "Представление" — используйте парсинг через СтрРазделить или регулярные выражения, но обязательно выполняйте итоговое сопоставление через запрос с временной таблицей для обеспечения высокой скорости работы системы.