При обработке текстовых данных в 1С часто возникает задача поиска числовых последовательностей: от номеров документов и артикулов до произвольных цифр в тексте. Рассмотрим, как правильно составлять регулярные выражения для поиска цифр переменной и фиксированной длины, а также разберем нюансы работы с движком VBScript.RegExp и встроенными функциями платформы 1С.
Рассмотрим базовый сценарий: необходимо найти в строке любую непрерывную группу цифр, длина которой заранее неизвестна.
Для обозначения одиночной цифры в регулярных выражениях применяется класс [0-9] или метасимвол \d. Чтобы указать, что цифра должна repeating один или более раз, используется квантификатор + (эквивалентен записи {1,}).
Сформулируем варианты шаблона:
[0-9]+ — ищет последовательность из одной или более цифр.\d+ — эквивалентная и более краткая запись.Посмотрим на пример использования COM-объекта VBScript.RegExp во встроенном языке 1С:
RegExp = Новый COMОбъект("VBScript.RegExp");
RegExp.IgnoreCase = Ложь;
RegExp.Global = Истина;
RegExp.Pattern = "\d+";
СтрокаИсточника = "В заказе № 12345 указано 67 позиций";
Matches = RegExp.Execute(СтрокаИсточника);
Для Каждого Элемент Из Matches Цикл
Сообщить(Элемент.Value); // Выведет 12345, затем 67
КонецЦикла;
Разберем более сложную ситуацию. Предположим, требуется найти последовательность формата XX-XXXX (2 цифры, дефис, от 1 до 4 цифр). При этом если перед первыми двумя цифрами идет еще одна цифра (например, 99912-123), такое совпадение должно игнорироваться целиком, а для строки абвгд12-123 значение должно находиться как 12-123 (без захвата буквы д).
Разберем подводные камни при решении этой задачи через VBScript.RegExp:
(?<!\d)\d{2}-\d{1,4} приведет к ошибке, так как движок VBScript.RegExp основан на стандарте ECMAScript 3 и не поддерживает конструкции просмотра назад.\b: Использование шаблона \b\d{2}-\d{1,4}\b сработает корректно с латиницей, но при наличии перед цифрой русской буквы (например, "текст12-34") сработает ошибочно. Метасимвол \w в VBScript включает только символы ASCII [a-zA-Z0-9_], из-за чего кириллица воспринимается как небуквенный символ \W, создавая границу слова \b на стыке с цифрой.Чтобы обойти ограничение по отсутствию Lookbehind в VBScript.RegExp, проанализируем подход с использованием групп (подмасок):
Шаблон: (\D|^)(\d{2}-\d{1,4})
Структура данного выражения:
(\D|^) — первая группа: требует наличия перед числом не-цифры (\D) либо начала строки (^).(\d{2}-\d{1,4}) — вторая группа: искомая комбинация из двух цифр, дефиса и 1–4 цифр.При совпадении с шаблоном в свойства объекта попадет весь фрагмент текста, но сама нужная подстрока будет находиться во второй группе. Извлечь её можно через коллекцию SubMatches:
RegExp = Новый COMОбъект("VBScript.RegExp");
RegExp.IgnoreCase = Истина;
RegExp.Global = Истина;
RegExp.Pattern = "(\D|^)(\d{2}-\d{1,4})";
СтрокаПоиска = "текст12-123 и 99912-123 а также 45-6789";
Совпадения = RegExp.Execute(СтрокаПоиска);
Для Каждого Совпадение Из Совпадения Цикл
// Выбираем вторую группу захвата (индекс 1)
НужныйФрагмент = Совпадение.SubMatches(1);
Сообщить(НужныйФрагмент); // Выведет "12-123" и "45-6789"
КонецЦикла;
Начиная с версии 1С:Предприятие 8.3.23, в платформу встроен полнофункциональный механизм работы с регулярными выражениями стандарта ICU. Он работает кроссплатформенно (в том числе под Linux) и лишен ограничений VBScript.RegExp.
Посмотрим, как аналогичная задача решается встроенной функцией СтрНайтиВсеПоРегулярномуВыражению с применением негативной ретроспективной проверки (?<!\d):
СтрокаПоиска = "текст12-123 и 99912-123 а также 45-6789";
Шаблон = "(?<!\d)\d{2}-\d{1,4}";
МассивРезультатов = СтрНайтиВсеПоРегулярномуВыражению(СтрокаПоиска, Шаблон);
Для Каждого ЭлементИзРезультата Из МассивРезультатов Цикл
Сообщить(ЭлементИзРезультата.Значение);
КонецЦикла;
Конструкция (?<!\d) указывает движку убедиться, что перед двумя цифрами нет другой цифры, не добавляя при этом предшествующий символ в итоговый результат поиска.