Как найти последовательность цифр в строке с помощью регулярных выражений в 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При обработке текстовых данных в 1С часто возникает задача поиска числовых последовательностей: от номеров документов и артикулов до произвольных цифр в тексте. Рассмотрим, как правильно составлять регулярные выражения для поиска цифр переменной и фиксированной длины, а также разберем нюансы работы с движком VBScript.RegExp и встроенными функциями платформы 1С.

1. Поиск последовательности цифр произвольной длины

Рассмотрим базовый сценарий: необходимо найти в строке любую непрерывную группу цифр, длина которой заранее неизвестна.

Для обозначения одиночной цифры в регулярных выражениях применяется класс [0-9] или метасимвол \d. Чтобы указать, что цифра должна repeating один или более раз, используется квантификатор + (эквивалентен записи {1,}).

Сформулируем варианты шаблона:

  1. [0-9]+ — ищет последовательность из одной или более цифр.
  2. \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
КонецЦикла;

2. Ограничение длины и отсечение лишних символов

Разберем более сложную ситуацию. Предположим, требуется найти последовательность формата XX-XXXX (2 цифры, дефис, от 1 до 4 цифр). При этом если перед первыми двумя цифрами идет еще одна цифра (например, 99912-123), такое совпадение должно игнорироваться целиком, а для строки абвгд12-123 значение должно находиться как 12-123 (без захвата буквы д).

Разберем подводные камни при решении этой задачи через VBScript.RegExp:

  1. Отсутствие поддержки Lookbehind: Попытка использовать негативную ретроспективную проверку (?<!\d)\d{2}-\d{1,4} приведет к ошибке, так как движок VBScript.RegExp основан на стандарте ECMAScript 3 и не поддерживает конструкции просмотра назад.
  2. Особенности границы слова \b: Использование шаблона \b\d{2}-\d{1,4}\b сработает корректно с латиницей, но при наличии перед цифрой русской буквы (например, "текст12-34") сработает ошибочно. Метасимвол \w в VBScript включает только символы ASCII [a-zA-Z0-9_], из-за чего кириллица воспринимается как небуквенный символ \W, создавая границу слова \b на стыке с цифрой.

3. Решение задачи в VBScript.RegExp через группы захвата

Чтобы обойти ограничение по отсутствию Lookbehind в VBScript.RegExp, проанализируем подход с использованием групп (подмасок):

Шаблон: (\D|^)(\d{2}-\d{1,4})

Структура данного выражения:

  1. (\D|^) — первая группа: требует наличия перед числом не-цифры (\D) либо начала строки (^).
  2. (\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"
КонецЦикла;

4. Использование штатного механизма регулярных выражений 1С (платформа 8.3.23+)

Начиная с версии 1С:Предприятие 8.3.23, в платформу встроен полнофункциональный механизм работы с регулярными выражениями стандарта ICU. Он работает кроссплатформенно (в том числе под Linux) и лишен ограничений VBScript.RegExp.

Посмотрим, как аналогичная задача решается встроенной функцией СтрНайтиВсеПоРегулярномуВыражению с применением негативной ретроспективной проверки (?<!\d):


СтрокаПоиска = "текст12-123 и 99912-123 а также 45-6789";
Шаблон = "(?<!\d)\d{2}-\d{1,4}";

МассивРезультатов = СтрНайтиВсеПоРегулярномуВыражению(СтрокаПоиска, Шаблон);
Для Каждого ЭлементИзРезультата Из МассивРезультатов Цикл
    Сообщить(ЭлементИзРезультата.Значение);
КонецЦикла;

Конструкция (?<!\d) указывает движку убедиться, что перед двумя цифрами нет другой цифры, не добавляя при этом предшествующий символ в итоговый результат поиска.

← На главную