В процессе разработки часто возникает задача извлечения контактных данных из неструктурированного текста. Это может быть разбор тела электронного письма, обработка заявок с сайта или анализ логов. Для этой задачи есть инструмент анализа текстов HTTP-запросов в логах. Одной из самых распространенных подзадач является поиск адреса электронной почты (email). В этой статье мы подробно разберем несколько способов решения этой задачи, начиная от использования регулярных выражений и заканчивая встроенными функциями Библиотеки стандартных подсистем (БСП).
Если вы работаете на старых версиях платформы (например, 8.2 или ранние сборки 8.3) или в режиме обычного приложения под управлением Windows, классическим способом будет использование объекта VBScript.RegExp. В процессе разработки пригодится консоль кода для написания и тестирования алгоритмов. Рассмотрим, почему код может не работать и как его исправить.
Основная ошибка начинающих разработчиков заключается в использовании якорей начала ^ и конца $ строки в шаблоне. Эти символы заставляют движок искать соответствие всей строке целиком. Если в строке помимо email есть другой текст, функция вернет пустой результат. Проанализируем исправленный код:
Функция мПолучитьЭлПочтуОтправителя(Знач СтрокаПоиска)
// Убираем ^ и $, чтобы искать подстроку внутри текста
// Добавляем поддержку кириллицы для доменов .рф
Шаблон = "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Zа-яА-Я]{2,}";
Попытка
RegExp = Новый COMОбъект("VBScript.RegExp");
Исключение
Сообщить("Регулярные выражения недоступны на данном сервере/клиенте");
Возврат Новый Массив;
КонецПопытки;
RegExp.Global = Истина;
RegExp.IgnoreCase = Истина; // Игнорировать регистр букв
RegExp.Pattern = Шаблон;
Результат = Новый Массив;
Matches = RegExp.Execute(СтрокаПоиска);
Для Каждого Match Из Matches Цикл
Результат.Добавить(Match.Value);
КонецЦикла;
Возврат Результат;
КонецФункции
Важный нюанс: использование VBScript.RegExp ограничено операционной системой Windows. Если ваш сервер 1С работает под Linux, этот код вызовет исключение.
В современных версиях платформы 1С появились встроенные методы для работы с регулярными выражениями, которые работают кроссплатформенно и значительно быстрее. Отлаживать подобные алгоритмы удобнее через инструмент для написания и отладки кода в режиме 1С:Предприятие. Рассмотрим применение функции СтрНайтиВсеПоРегулярномуВыражению.
Этот метод возвращает массив объектов типа РезультатПоискаПоРегулярномуВыражению, что позволяет не только получить текст адреса, но и узнать его позицию в исходной строке.
Функция ИзвлечьАдресаСовременнымСпособом(Текст)
// Более строгий шаблон для поиска email
Шаблон = "[\w\d._%+-]+@[\w\d.-]+\.[\w]{2,}";
Результаты = СтрНайтиВсеПоРегулярномуВыражению(Текст, Шаблон);
СписокАдресов = Новый Массив;
Для Каждого ТекущийРезультат Из Результаты Цикл
СписокАдресов.Добавить(ТекущийРезультат.Значение);
КонецЦикла;
Возврат СписокАдресов;
КонецФункции
Проанализируем шаблон: [\w\d._%+-]+ означает поиск одного или более символов слова, цифр, точек или дефисов до знака "собаки". \.[\w]{2,} гарантирует, что в доменной зоне после точки будет как минимум два символа (например, .ru, .com).
Если ваша конфигурация построена на базе БСП (Библиотека стандартных подсистем), вам не нужно изобретать велосипед. В библиотеке уже реализованы надежные механизмы разбора строк с адресами. Рассмотрим использование общего модуля ОбщегоНазначенияКлиентСервер.
Функция АдресаЭлектроннойПочтыИзСтроки удобна тем, что она умеет обрабатывать сложные строки, где адреса разделены запятыми или точками с запятой, а также содержат имена получателей в формате Имя <email@domain.com>.
// Пример использования БСП
ТекстСАдресами = "Иван Иванов <ivan@test.ru>, support@company.com; почта: info@service.рф";
МассивСтруктур = ОбщегоНазначенияКлиентСервер.АдресаЭлектроннойПочтыИзСтроки(ТекстСАдресами);
Для Каждого СтрАдрес Из МассивСтруктур Цикл
// СтрАдрес содержит поля: Адрес, Представление
Сообщить("Найден адрес: " + СтрАдрес.Адрес);
КонецЦикла;
Этот метод является наиболее рекомендуемым для использования в типовых конфигурациях (ЕРП, КА, УТ 11, БП 3.0), так как он учитывает множество нюансов форматирования, которые сложно предусмотреть в простой регулярке.
В некоторых случаях, когда использование регулярных выражений по каким-то причинам невозможно или нежелательно, можно прибегнуть к ручному разбору строки. Для подобных задач по извлечению данных есть обработка для распознавания реквизитов из текста счета. Разберем логику: нам нужно найти символ @, а затем "развернуть" строку влево и вправо до ближайших разделителей (пробелов, кавычек, скобок).
Функция ИзвлечьEmailВручную(Знач ВходнаяСтрока)
Разделители = " ,;()<>[]{}!/|'""\?" + Символы.ПС + Символы.ВК + Символы.Таб;
ПозицияСобаки = СтрНайти(ВходнаяСтрока, "@");
Если ПозицияСобаки = 0 Тогда
Возврат "";
КонецЕсли;
// Ищем начало адреса влево от @
НачалоАдреса = 1;
Для Счетчик = 1 По ПозицияСобаки - 1 Цикл
Символ = Сред(ВходнаяСтрока, ПозицияСобаки - Счетчик, 1);
Если СтрНайти(Разделители, Символ) > 0 Тогда
НачалоАдреса = ПозицияСобаки - Счетчик + 1;
Прервать;
КонецЕсли;
КонецЦикла;
// Ищем конец адреса вправо от @
КонецАдреса = СтрДлина(ВходнаяСтрока);
Для Счетчик = 1 По КонецАдреса - ПозицияСобаки Цикл
Символ = Сред(ВходнаяСтрока, ПозицияСобаки + Счетчик, 1);
Если СтрНайти(Разделители, Символ) > 0 Тогда
КонецАдреса = ПозицияСобаки + Счетчик - 1;
Прервать;
КонецЕсли;
КонецЦикла;
Результат = Сред(ВходнаяСтрока, НачалоАдреса, КонецАдреса - НачалоАдреса + 1);
// Простейшая проверка на корректность (наличие точки после @)
Если СтрНайти(Результат, ".", , СтрНайти(Результат, "@")) > 0 Тогда
Возврат Результат;
Иначе
Возврат "";
КонецЕсли;
КонецФункции
Выясним, какой метод лучше выбрать в зависимости от ситуации:
Важный совет по валидации: Помните, что наличие строки, похожей на email, не гарантирует существование самого ящика. Единственный 100% надежный способ проверить адрес — отправить на него письмо с кодом подтверждения. Однако для первичной очистки данных регулярные выражения остаются незаменимым инструментом. Для этих задач есть сервис ИИ для извлечения реквизитов и контактных данных.
При составлении шаблонов также учитывайте возможность существования национальных доменов (типа .рф, .бел, .қаз). Если ваша система предполагает работу с СНГ-рынком, обязательно включайте диапазоны кириллицы а-яА-Я в регулярное выражение или используйте универсальные категории символов.