При обработке текстовых данных, наименований номенклатуры, характеристик или при загрузке информации из внешних источников часто возникает задача извлечь дату, которая находится внутри произвольного текста (например, "Поступление, 15.11.2023, партия 1"), и преобразовать найденный фрагмент в стандартный тип Дата платформы 1С. Рассмотрим по шагам, как решить эту задачу, какие методы применить и как избежать типичных ошибок времени выполнения.
Для гибкого поиска шаблона даты вида ДД.ММ.ГГГГ в произвольном тексте удобно использовать механизм регулярных выражений. В операционной системе Windows для этого традиционно применяется объект VBScript.RegExp.
Посмотрим на пример извлечения даты:
Регуляр = Новый COMОбъект("VBScript.RegExp");
Регуляр.IgnoreCase = Истина; // Игнорировать регистр
Регуляр.Global = Истина; // Поиск всех вхождений шаблона
Регуляр.Pattern = "\b\d{2}\.\d{2}\.\d{4}\b"; // Шаблон даты ДД.ММ.ГГГГ
// Исходная строка для анализа
СтрокаДляПоиска = Строка(СтрокаТабличнойЧасти.ХарактеристикаНоменклатуры);
Результаты = Регуляр.Execute(СтрокаДляПоиска);
Для Каждого Совпадение Из Результаты Цикл
НайденнаяПодстрока = Совпадение.Value;
Сообщить("Найдена дата в тексте: " + НайденнаяПодстрока);
// Преобразуем найденную подстроку в тип Дата
НашаДата = ПреобразоватьСтрокуДДММГГГГВДату(НайденнаяПодстрока);
Сообщить("Тип 1С Дата: " + Строка(НашаДата));
КонецЦикла;
Выясним причину распространенной ошибки, возникающей при передаче значения в метод Execute. Метод Execute COM-объекта принимает исключительно строковые данные (тип BSTR). Если в метод передается реквизит составного типа, ссылка на элемент справочника (например, СправочникСсылка.ХарактеристикиНоменклатуры), значение Неопределено или NULL, платформа 1С вызывает исключение несовпадения типов.
Чтобы избежать ошибки, обязательно приводим анализируемое значение к строковому типу с помощью встроенной функции: Строка(ЗначениеРеквизита).
После того как дата выделена из текста в виде строки "10.10.2017", попытка выполнить вызов Дата("10.10.2017") приведет к фатальной ошибке: «Преобразование значения к типу Дата не может быть выполнено».
Проанализируем ситуацию: стандартный конструктор Дата() при получении строкового аргумента ожидает строго канонический формат без точек: "ГГГГММДД" или "ГГГГММДДЧЧММСС". Строку формата с точками конструктор напрямую распознать не может.
Преобразовать строку в дату можно несколькими надежными путями:
Разберем строку на составляющие (день, месяц, год) с помощью функций Лев(), Сред(), Прав() и объединим их в каноническую строку "ГГГГММДД":
Функция ПреобразоватьСтрокуДДММГГГГВДату(СтрДата) Экспорт
// Формат строки: "ДД.ММ.ГГГГ" (10 символов)
Если СтрДлина(СтрДата) <> 10 Тогда
Возврат '00010101';
КонецЕсли;
ДеньСтр = Лев(СтрДата, 2);
МесяцСтр = Сред(СтрДата, 4, 2);
ГодСтр = Сред(СтрДата, 7, 4);
КаноническаяСтрока = ГодСтр + МесяцСтр + ДеньСтр;
Попытка
Возврат Дата(КаноническаяСтрока);
Исключение
// Перехват некорректных дат (например, 31.02.2023)
Возврат '00010101';
КонецПопытки;
КонецФункции
Конструктор Дата(Год, Месяц, День) принимает числа. Выделим подстроки, преобразуем их к типу Число и передадим в конструктор:
Попытка
День = Число(Лев(СтрДата, 2));
Месяц = Число(Сред(СтрДата, 4, 2));
Год = Число(Сред(СтрДата, 7, 4));
РезультатДата = Дата(Год, Месяц, День);
Исключение
РезультатДата = '00010101';
КонецПопытки;
Если в конфигурации внедрена БСП, воспользуемся готовой библиотечной функцией, которая умеет безопасно преобразовывать строки формата ДД.ММ.ГГГГ:
РезультатДата = СтроковыеФункцииКлиентСервер.СтрокаВДату(СтрДата);
При работе на сервере под управлением Linux или в веб-клиенте вызов COMОбъект("VBScript.RegExp") завершится ошибкой, так как COM-технология доступна исключительно в среде Windows. В таких условиях задачу можно решить штатными строковыми функциями платформы 1С.
Рассмотрим алгоритм разбора строки по разделителям:
Функция НайтиДатуВТекстеБезCOM(ИсходныйТекст) Экспорт
// Заменяем распространенные знаки препинания на пробелы для разделения слов
ОчищеннаяСтрока = СтрЗаменить(ИсходныйТекст, ",", " ");
ОчищеннаяСтрока = СтрЗаменить(ОчищеннаяСтрока, ";", " ");
МассивСлов = СтрРазделить(ОчищеннаяСтрока, " ", Ложь);
Для Каждого Слово Из МассивСлов Цикл
Слово = СокрЛП(Слово);
// Проверяем формат ДД.ММ.ГГГГ: длина ровно 10 символов и точки на 3 и 6 позициях
Если СтрДлина(Слово) = 10 И Сред(Слово, 3, 1) = "." И Сред(Слово, 6, 1) = "." Тогда
Попытка
День = Число(Лев(Слово, 2));
Месяц = Число(Сред(Слово, 4, 2));
Год = Число(Сред(Слово, 7, 4));
Если День >= 1 И День <= 31 И Месяц >= 1 И Месяц <= 12 И Год >= 1900 И Год <= 2099 Тогда
Возврат Дата(Год, Месяц, День);
КонецЕсли;
Исключение
// Не является корректным числом или датой, продолжаем поиск
КонецПопытки;
КонецЕсли;
КонецЦикла;
Возврат '00010101';
КонецФункции
Важные рекомендации:
Попытка ... Исключение, так как некорректная календарная дата (например, 29 февраля невисокосного года) приводит к аварийной остановке выполнения модуля.