Часто при работе с регулярными выражениями в 1С возникает ситуация, когда шаблон, отлично работающий на онлайн-тестерах, отказывается находить совпадения с кириллическими словами. Особенно это касается использования метасимвола границы слова \b. Давайте вместе разберемся, почему так происходит и какие есть способы решить эту задачу.
Проанализируем ситуацию и рассмотрим несколько надежных решений, которые помогут вам правильно обрабатывать текст на русском языке.
\b не работает с кириллицей?Чтобы понять корень проблемы, нужно знать, какой механизм (или "движок") регулярных выражений используется в вашей версии платформы 1С. Исторически сложилось так, что подходы менялись, и это напрямую влияет на результат.
Старые версии платформы (до 8.3.23)
В этих версиях не было встроенной поддержки регулярных выражений. Для работы с ними разработчики обычно использовали внешний COM-объект VBScript.RegExp. Ключевая особенность этого движка в том, что он не полностью поддерживает Unicode. Метасимвол границы слова \b в нем корректно работает только со словами, состоящими из латинских букв [a-zA-Z] и цифр. Кириллические символы он не считает "словесными", поэтому и не может определить границу русского слова.
Современные версии платформы (начиная с 8.3.23)
Начиная с этой версии, в 1С появилась нативная поддержка регулярных выражений. Она основана на мощной библиотеке ICU (International Components for Unicode). Этот движок полностью поддерживает Unicode, а значит, проблема с определением границ кириллических слов в нем должна быть решена. Однако, чтобы им воспользоваться, необходимо использовать новые встроенные функции языка 1С.
Теперь, когда мы понимаем причины, давайте перейдем к конкретным решениям.
Это самый правильный и рекомендуемый способ для современных конфигураций. Вместо устаревших подходов используем новые встроенные функции, которые работают на движке ICU.
Разберем по шагам, что нужно делать.
Определимся с функцией. В 1С есть несколько функций, и важно выбрать правильную:
СтрПодобнаПоРегулярномуВыражению() — проверяет, соответствует ли вся строка целиком шаблону. Часто именно из-за неправильного выбора этой функции возникает ошибка, так как она ищет не вхождение, а полное совпадение.СтрНайтиПоРегулярномуВыражению() — ищет первое вхождение подстроки, соответствующей шаблону. Эта функция подходит для большинства задач по поиску.СтрЗаменитьПоРегулярномуВыражению() — находит и заменяет все вхождения по шаблону.Составим правильный шаблон. В движке ICU метасимвол \b должен корректно работать с кириллицей. Посмотрим на пример поиска отдельного слова "арка".
ИсходнаяСтрока = "Эта арка была построена давно, аркада вела в сад.";
Шаблон = "\bарка\b";
// Используем функцию для поиска вхождения
РезультатПоиска = СтрНайтиПоРегулярномуВыражению(ИсходнаяСтрока, Шаблон);
Если РезультатПоиска <> Неопределено Тогда
// РезультатПоиска - это объект "РезультатПоискаПоРегулярномуВыражению"
// Он содержит Позицию и Длину найденного фрагмента
Сообщить("Слово 'арка' найдено на позиции: " + РезультатПоиска.Позиция);
Иначе
Сообщить("Слово 'арка' не найдено.");
КонецЕсли;
Важный момент: если вы хотите найти слово, но ваша строка содержит еще что-то, не используйте СтрПодобнаПоРегулярномуВыражению. Она вернет Ложь, так как вся строка "Эта арка была..." не равна шаблону "\bарка\b". Эта функция подошла бы, если бы ИсходнаяСтрока была равна просто "арка".
Этот метод подойдет, если вы работаете на старой версии платформы или если по какой-то причине \b в вашей среде все равно ведет себя некорректно. Мы заменим \b на более надежную конструкцию, которая явно указывает, что до и после нашего слова не должно быть других букв.
Для этого воспользуемся так называемыми ретроспективной (lookbehind) и опережающей (lookahead) проверками.
Разберем подробнее, как это работает:
(? — это негативная ретроспективная проверка (negative lookbehind). Она проверяет, что перед текущей позицией нет символа, который является буквой в любом языке (\p{L} — класс символов Unicode "Буква").(?!\p{L}) — это негативная опережающая проверка (negative lookahead). Она проверяет, что после текущей позиции нет символа, который является буквой.Таким образом, мы вручную создаем аналог "границы слова", который гарантированно будет работать с Unicode.
Посмотрим на пример. Наш шаблон для поиска слова "арка" будет выглядеть так: (?. Он найдет "арка" в строке "эта арка!", но не найдет в слове "аркада".
Давайте посмотрим, как это будет выглядеть в коде для старой платформы с использованием VBScript.RegExp.
// Этот код для старых версий платформы 1С
Попытка
RegEx = Новый COMОбъект("VBScript.RegExp");
Исключение
Сообщить("Не удалось создать COM-объект VBScript.RegExp.");
Возврат;
КонецПопытки;
ИсходнаяСтрока = "Эта арка была построена давно, аркада вела в сад.";
// Указываем, что ищем все вхождения (Global = True)
// и не учитываем регистр (IgnoreCase = True)
RegEx.Global = Истина;
RegEx.IgnoreCase = Истина;
RegEx.Pattern = "(? 0 Тогда
ПервоеСовпадение = НайденныеСовпадения.Item(0);
Сообщить("Слово 'арка' найдено на позиции: " + (ПервоеСовпадение.FirstIndex + 1));
Иначе
Сообщить("Слово 'арка' не найдено.");
КонецЕсли;
Обратите внимание: движок VBScript.RegExp может не поддерживать классы Unicode, такие как \p{L}. В этом случае можно использовать более простое, но менее универсальное выражение, перечислив кириллические символы явно: (?<
← К списку