Регулярные выражения — это мощный инструмент для поиска и обработки текста, который значительно сокращает объем кода по сравнению со стандартными строковыми функциями. Однако в среде 1С программисты часто сталкиваются с тем, что привычные конструкции, работающие в онлайн-тестерах (например, на regex101.com), отказываются работать внутри кода 1С. В этой статье мы подробно разберем, почему возникают ошибки в регулярных выражениях, как обойти ограничения движка VBScript.RegExp и какие современные альтернативы появились в платформе 1С.
Рассмотрим ситуацию: нам нужно найти слово "Маша" как отдельное слово, чтобы перед ним и после него не было других букв или цифр. Стандартная регулярка для этого выглядит так: (?<![\wа-яА-Я])Маша(?![\wа-яА-Я]). В этой строке используются две важные проверки:
Проблема заключается в том, что объект VBScript.RegExp, который традиционно используется в 1С через COM-соединение, был разработан очень давно и не поддерживает ретроспективные проверки (lookbehind). Именно на этой части выражения 1С выдает ошибку "Ошибка при вызове метода контекста". Опережающие проверки (lookahead) при этом поддерживаются, что создает путаницу у разработчиков.
Если мы не можем использовать lookbehind, нам нужно найти другой способ ограничить поиск. Разберем ситуацию, когда нам нужно найти слово целиком, не затрагивая окружающие символы. Вместо "проверки без поглощения" мы можем включить окружающие символы в поиск, но выделить само целевое слово в группу захвата.
Проанализируем исправленный вариант регулярного выражения для поиска слова "Маша" с учетом кириллицы и специфики VBScript.RegExp:
// Шаблон для поиска:
// ([^\wА-Яа-я0-9ёЁ]|^)Маша(?![\wа-яА-ЯёЁ])
Разберем это выражение по частям:
^). Мы берем это в скобки, чтобы создать группу захвата №1.Важное замечание про букву "Ё": В стандартных диапазонах А-Я буква ё (и заглавная Ё) часто не учитывается, так как в таблице Unicode она стоит отдельно. Чтобы ваш поиск работал корректно для всех русских имен и слов, всегда добавляйте ёЁ в наборы символов вручную.
Рассмотрим пример кода на языке 1С для замены слова целиком с использованием этого метода:
РегВыр = Новый COMОбъект("VBScript.RegExp");
РегВыр.Global = Истина;
РегВыр.IgnoreCase = Истина;
// Используем группы, чтобы сохранить символы ПЕРЕД словом
РегВыр.Pattern = "([^а-яА-ЯёЁ0-9]|^)Маша(?![а-яА-ЯёЁ0-9])";
ИсходныйТекст = "Маша ела Кашу, а Машаша не ела. <Маша> сидела.";
// При замене $1 возвращает то, что было найдено в первых скобках (границу слова)
Результат = РегВыр.Replace(ИсходныйТекст, "$1Дарья");
// Результат: "Дарья ела Кашу, а Машаша не ела. <Дарья> сидела."
Многие знают про спецсимвол \b, который обозначает границу слова. Казалось бы, выражение \bМаша\b должно решить проблему. Однако в движке VBScript символ \b работает корректно только с латиницей. Для кириллицы границы слова определяются некорректно, так как русские буквы не входят в категорию "word characters" (\w) данного старого движка. Поэтому ручное перечисление допустимых или недопустимых символов, как показано выше, является более надежным путем для 1С-разработчика.
Важно знать, что начиная с версии платформы 8.3.24, компания 1С добавила нативную поддержку регулярных выражений. Теперь не нужно использовать нестабильные COM-объекты. Новый объект РегулярноеВыражение основан на библиотеке ICU и поддерживает все современные возможности, включая ретроспективные проверки.
Посмотрим, как изменится решение задачи на новой платформе:
// Используем нативный объект 1С (8.3.24+)
Шаблон = "(?<![\wа-яА-ЯёЁ])Маша(?![\wа-яА-ЯёЁ])";
РегВыр = Новый РегулярноеВыражение(Шаблон, ПараметрыРегулярногоВыражения.БезУчетаРегистра);
Текст = "Маша ела кашу";
Результат = РегВыр.Заменить(Текст, "Дарья");
Этот код будет работать в точности так же, как в современных языках программирования и онлайн-отладчиках. Если у вас есть возможность обновить версию платформы — это лучшее решение проблемы.
В сообществе 1С часто спорят о целесообразности использования регулярок. Проанализируем аргументы сторон. Противники утверждают, что регулярные выражения сложно читать и отлаживать (так называемый "write-only code"). Сторонники же указывают на компактность. Для сравнения, попробуем написать функцию проверки корректности Email без регулярных выражений:
Функция ЕмейлПравильный(Адрес)
// Очень упрощенная проверка
Если СтрЧислоВхождений(Адрес, "@") <> 1 Тогда
Возврат Ложь;
КонецЕсли;
Части = СтрРазделить(Адрес, "@");
Домен = Части[1];
Если СтрЧислоВхождений(Домен, ".") = 0 Тогда
Возврат Ложь;
КонецЕсли;
Возврат Истина;
КонецФункции
Этот код занимает 15 строк и при этом он крайне несовершенен: он пропустит адреса с пробелами, спецсимволами или недопустимыми доменами. Аналогичная проверка регулярным выражением займет 1-2 строки и будет гораздо точнее. Главное правило работы с регулярками в 1С: всегда оставляйте комментарий рядом с шаблоном, объясняющий, что именно он ищет. Это снимет все вопросы коллег при последующем чтении кода.
Чтобы не тратить время на перезапуск 1С при каждой правке шаблона, рекомендуем использовать специализированные инструменты:
VBScript.RegExp. Это важно, так как онлайн-тестеры обычно используют движки PHP, Python или JavaScript, которые мощнее "старого" COM-объекта Windows.debuggex.com позволяют увидеть схему работы регулярки, что помогает понять, где именно "застревает" поиск.Подводя итог, можно сказать: если вы работаете на старых версиях платформы, забудьте про lookbehind и используйте группы захвата ($1, $2) для сохранения контекста вокруг искомого слова. Если же вы на актуальной платформе — переходите на объект РегулярноеВыражение, который лишен детских болезней старых технологий.