При рефакторинге информационных баз или миграции данных часто возникает задача разбора неструктурированных строковых полей, в которые пользователи годами вводили даты вручную в произвольном виде — например, «2 квартал 2015 г.», «за период 2013-2014» или «15.03.2022». Разберем, какими способами можно программно найти четырехзначный год в тексте, выбрать наиболее актуальное значение и корректно преобразовать его в тип Дата.
Если конфигурация работает под управлением операционной системы Windows, одним из классических и быстрых вариантов поиска паттернов является вызов COM-объекта VBScript.RegExp. Разберем по шагам, как извлечь все четырехзначные числа из переданной строки:
RegExp = Новый COMОбъект("VBScript.RegExp");
RegExp.IgnoreCase = Истина;
RegExp.Global = Истина;
RegExp.MultiLine = Истина;
RegExp.Pattern = "\b(19|20)\d{2}\b"; // Поиск годов 20 и 21 веков
ИсходнаяСтрока = "Пример: 2 квартал 2015 г. или 2013-2014";
Matches = RegExp.Execute(ИсходнаяСтрока);
МаксимальныйГод = 0;
Для Сч = 0 По Matches.Count - 1 Цикл
Match = Matches.Item(Сч);
ГодЧислом = Число(Match.Value);
Если ГодЧислом > МаксимальныйГод Тогда
МаксимальныйГод = ГодЧислом;
КонецЕсли;
КонецЦикла;
Если МаксимальныйГод > 0 Тогда
ИтоговаяДата = Дата(МаксимальныйГод, 1, 1);
КонецЕсли;
Обратим внимание на шаблон регулярного выражения: вместо простого \d{4} безопаснее использовать шаблон с границами слов и префиксами веков \b(19|20)\d{2}\b. Это защитит алгоритм от ложных срабатываний при наличии длинных артикулов, номеров накладных или сумм (например, строка «12015» не будет ошибочно распознана как 2015 год).
Ограничения использования COM-объекта:
Новый COMОбъект("VBScript.RegExp") внутри цикла обхода строк табличной части или выборки документов. Создавайте экземпляр один раз перед началом массовой обработки данных.Начиная с версии платформы 8.3.23, в 1С появилась встроенная кроссплатформенная поддержка регулярных выражений. Это рекомендуемый способ, так как он работает на любых ОС без использования внешних библиотек.
Посмотрим на пример использования функций СтрПодобнаПоРегулярномуВыражению и СтрНайтиПоРегулярномуВыражению:
ШаблонГода = "\b(19|20)\d{2}\b";
СтрокаДляПоиска = "2 квартал 2015 г.";
Если СтрПодобнаПоРегулярномуВыражению(СтрокаДляПоиска, ".*" + ШаблонГода + ".*") Тогда
РезультатПоиска = СтрНайтиПоРегулярномуВыражению(СтрокаДляПоиска, ШаблонГода);
Если РезультатПоиска <> Неопределено Тогда
НайденнаяПодстрока = Сред(СтрокаДляПоиска, РезультатПоиска.НачальнаяПозиция, РезультатПоиска.Длина);
НайденныйГод = Число(НайденнаяПодстрока);
ДатаРезультат = Дата(НайденныйГод, 1, 1);
КонецЕсли;
КонецЕсли;
Если требуется универсальное решение без COM-объектов, работающее на старых версиях платформы 1С, применим алгоритм последовательного обхода строки с выделением непрерывных цифровых блоков:
Функция ИзвлечьМаксимальныйГодИзСтроки(Знач ИсходныйТекст)
МаксГод = 0;
Цифры = "0123456789";
ТекущийБлок = "";
Для Позиция = 1 По СтрДлина(ИсходныйТекст) Цикл
Символ = Сред(ИсходныйТекст, Позиция, 1);
Если СтрНайти(Цифры, Символ) > 0 Тогда
ТекущийБлок = ТекущийБлок + Символ;
Иначе
Если СтрДлина(ТекущийБлок) = 4 Тогда
ЧислоБлока = Число(ТекущийБлок);
Если ЧислоБлока >= 1900 И ЧислоБлока <= 2099 Тогда
МаксГод = Макс(МаксГод, ЧислоБлока);
КонецЕсли;
КонецЕсли;
ТекущийБлок = "";
КонецЕсли;
КонецЦикла;
// Проверка блока, если строка заканчивается цифрой
Если СтрДлина(ТекущийБлок) = 4 Тогда
ЧислоБлока = Число(ТекущийБлок);
Если ЧислоБлока >= 1900 И ЧислоБлока <= 2099 Тогда
МаксГод = Макс(МаксГод, ЧислоБлока);
КонецЕсли;
КонецЕсли;
Возврат МаксГод;
КонецФункции
Такой подход полностью автономен, не требует сторонних компонентов и отсекает пятизначные числа за счет проверки длины накопительного буфера.
Для разовых задач обработки данных можно воспользоваться методом перебора диапазона предполагаемых годов через функцию СтрНайти (или Найти в обычном приложении). Обязательно форматируем число без разделителей групп (параметр ЧГ=0), чтобы исключить неразрывные пробелы:
НайденныйГод = 0;
Для ПроверяемыйГод = 1990 По 2030 Цикл
ПодстрокаГода = Формат(ПроверяемыйГод, "ЧГ=0");
Если СтрНайти(СтрокаСГодом, ПодстрокаГода) > 0 Тогда
НайденныйГод = ПроверяемыйГод;
КонецЕсли;
КонецЦикла;
При заполнении новых реквизитов в исторических документах рекомендуем соблюдать следующие правила:
ДокументОбъект.ОбменДанными.Загрузка = Истина.