При автоматизации обработки входящей почты в 1С часто возникает задача парсинга (разбора) текста письма. Типичный пример — получение заявок с сайта, где данные клиента (имя, телефон, VIN-номер) приходят в теле письма в виде неструктурированного или слабоструктурированного текста. Рассмотрим, как эффективно решить эту задачу, используя механизмы регулярных выражений.
Долгое время основным способом работы с регулярными выражениями в среде 1С было использование внешнего объекта VBScript.RegExp. Этот метод до сих пор актуален для систем, работающих под управлением Windows. Разберем по шагам, как настроить этот объект и извлечь нужные данные.
Для начала проанализируем инициализацию объекта и его ключевые свойства:
RegExp = Новый COMОбъект("VBScript.RegExp");
RegExp.IgnoreCase = Истина; // Игнорировать регистр (А=а)
RegExp.Global = Истина; // Поиск всех вхождений, а не только первого
RegExp.MultiLine = Истина; // Текст рассматривается как многострочный
Когда мы ищем конкретные данные, такие как имя клиента, нам важно не просто найти слово "Имя", но и захватить текст, который идет следом за ним. Для этого используются захватывающие группы (круглые скобки в шаблоне). Посмотрим на пример кода, который извлекает имя, находящееся между маркером "Имя:" и каким-либо завершающим символом (например, тегом или переносом строки):
// Шаблон ищет текст после слова "Имя:" до ближайшего символа "<"
RegExp.Pattern = "Имя: (.*?)<";
Matches = RegExp.Execute(СодержаниеПисьма);
Если Matches.Count > 0 Тогда
// Получаем первое совпадение
Match = Matches.Item(0);
// Извлекаем только то, что попало в скобки (SubMatches)
ФИО = Match.SubMatches.Item(0);
Сообщить("Найден клиент: " + ФИО);
КонецЕсли;
Важный нюанс: использование Match.SubMatches.Item(0) позволяет отсечь сам маркер "Имя:" и получить только полезную нагрузку. Если использовать просто Match.Value, вы получите всю строку целиком, включая поисковый запрос.
Проанализируем современные возможности платформы. Начиная с версии 8.3.24, в 1С появилась родная поддержка регулярных выражений. Это критически важно для систем, работающих на Linux, так как COM-объекты там недоступны. Кроме того, встроенные механизмы работают быстрее.
Рассмотрим, как будет выглядеть поиск телефона и имени с использованием новых объектов РегулярноеВыражение и РезультатПоискаРегулярногоВыражения:
// Создаем объект регулярного выражения
// Паттерн для поиска телефона в форматах +7... или 8...
ПаттернТелефон = "((\+7|8)[\s\-]?\(?\d{3}\)?[\s\-]?\d{3}[\s\-]?\d{2}[\s\-]?\d{2})";
РегВыр = Новый РегулярноеВыражение(ПаттернТелефон);
// Ищем совпадения в тексте
Результат = РегВыр.Найти(ТекстПисьма);
Для Каждого Совпадение Из Результат Цикл
Телефон = Совпадение.Значение;
Сообщить("Найден номер: " + Телефон);
КонецЦикла;
Встроенные выражения поддерживают стандарт PCRE, что дает программисту гораздо больше гибкости в управлении поиском.
Разберем одну из самых частых ошибок начинающих — использование "жадных" квантификаторов. Посмотрим на ситуацию: в письме много звездочек или разделителей, и шаблон Имя.*(.*) может "проглотить" весь остаток письма вместо одной строки.
Чтобы ограничить поиск, используем ленивый квантификатор .*?. Рассмотрим разницу:
.*): захватит текст от слова "Имя" до самого последнего символа в письме..*?): остановится сразу, как только встретит следующий символ, указанный в шаблоне (например, перенос строки или разделитель).Проанализируем пример для сложной структуры со звездочками, как в исходном вопросе:
// Ищем текст между "Имя" и следующим блоком данных "Телефон"
// Учитываем возможные переносы строк (\n) и служебные символы (\*)
RegExp.Pattern = "Имя\*+([\s\S]*?)Телефон";
Часто регулярное выражение не срабатывает из-за невидимых символов. Письма в формате HTML могут содержать неразрывные пробелы ( ) или специфические кодировки. Перед запуском поиска крайне рекомендуется выполнить предварительную очистку текста.
Выясним причины возможных неудач и устраним их:
Символы.НПП на обычный пробел.Пример предварительной обработки:
ТекстДляПоиска = СтрЗаменить(Содержание.Текст, Символы.НПП, " ");
ТекстДляПоиска = СтрЗаменить(ТекстДляПоиска, Символы.Таб, " ");
// Теперь можно применять RegExp.Execute(ТекстДляПоиска)
Вместо того чтобы полагаться на жесткую структуру письма (количество звездочек или пробелов), лучше использовать более универсальные паттерны, которые ищут сами данные, а не их окружение.
Для поиска ФИО (Кириллица):
Шаблон ([А-ЯЁ][а-яё]+\s+[А-ЯЁ][а-яё]+(?:\s+[А-ЯЁ][а-яё]+)?) ищет слова, начинающиеся с заглавной буквы. Это позволит найти "Иван Иванович Иванов" даже если структура письма изменится.
Для поиска Телефона:
Шаблон ((\+7|8)[\s\-]?\(?\d{3}\)?[\s\-]?\d{3}[\s\-]?\d{2}[\s\-]?\d{2}) учитывает наличие скобок, тире и пробелов в номере телефона. Это гораздо надежнее, чем искать "все символы после слова Телефон".
Таким образом, комбинируя методы очистки текста, ленивые квантификаторы и группы захвата SubMatches, мы создаем отказоустойчивый механизм обработки почтовых сообщений в 1С.