В процессе работы с данными в 1С часто возникает задача извлечения нужной информации из неструктурированных текстовых строк. Одна из таких задач — получение названия города из адреса, который пользователи вводят в произвольной форме. Рассмотрим, как подойти к этой проблеме с помощью регулярных выражений, с какими сложностями можно столкнуться и какие существуют более надежные альтернативы.
Представим, что у нас есть строка с адресом, и изначально мы рассчитывали на строгий формат, например:
"РФ, 119334, (Москва, ул. Вавилова, дом № 5...)"
Для такого формата можно было бы использовать простое регулярное выражение, которое ищет текст между первой открывающей скобкой и первой запятой. Однако на практике пользователи вводят данные совершенно по-разному. Проанализируем возможные варианты:
"РФ, г.Москва, ул. Вавилова, дом № 5..." — город указан с префиксом "г." и без скобок."РФ, 119334, (г.Москва, ул. Вавилова...)" — префикс "г." внутри скобок."ул. Вавилова, дом № 5..., г.Москва" — город находится в конце строки."РФ, г. Москва, ул. Вавилова..." — после "г." может быть пробел.Более того, проблема усугубляется, когда мы вспоминаем о других типах населенных пунктов:
Иногда встречаются и более сложные случаи, когда в одной строке указано несколько населенных пунктов, например: "г. ТакойТо, пгт. Сякой". Все это делает задачу извлечения данных с помощью одного простого шаблона практически невыполнимой.
Первая мысль — составить регулярное выражение, которое будет искать один из префиксов ("г.", "с." и т.д.) и забирать следующее за ним слово. Однако здесь нас поджидает важная техническая особенность платформы 1С.
Платформа 1С:Предприятие использует библиотеку ICU (International Components for Unicode) для работы с регулярными выражениями. Это означает, что синтаксис, который вы успешно протестировали на популярных онлайн-сервисах (вроде regex101), может не сработать в 1С. Многие онлайн-инструменты по умолчанию используют движок PCRE (Perl Compatible Regular Expressions), синтаксис которого может отличаться.
Чаще всего проблемы возникают со сложными конструкциями, такими как lookbehind (просмотр назад), которые позволяют найти совпадение, которому что-то предшествует, не включая это "что-то" в результат. Если ваше выражение работает везде, кроме 1С, — причина почти наверняка в несовместимости синтаксиса с ICU.
Давайте попробуем составить более универсальный шаблон, ориентируясь на синтаксис ICU, и использовать захватывающие группы, которые работают более стабильно. Наша задача — найти префикс, необязательные пробелы после него и захватить идущее следом название населенного пункта.
Посмотрим на пример кода. Здесь мы используем функцию СтрНайтиПоРегулярномуВыражению, которая возвращает объект СоответствиеРегулярногоВыражения. У этого объекта есть метод ПолучитьГруппу(), который позволяет получить доступ к захваченным частям строки.
Процедура НайтиГородВСтроке()
НаименованиеОфиса1 = "РФ, г.Москва, ул. Вавилова, дом № 5";
НаименованиеОфиса2 = "РФ, 119334, (г. Москва, ул. Вавилова, дом № 5)";
НаименованиеОфиса3 = "ул. Вавилова, дом № 5, с.Ивановка";
НаименованиеОфиса4 = "д. Простоквашино, дом у реки";
// Составим шаблон, который ищет один из префиксов (г, с, пгт, д, пос),
// за которым следует точка, потом необязательные пробелы.
// Название населенного пункта (состоящее из букв, дефисов и пробелов)
// заключается в скобки - это и есть наша захватываемая группа.
// Флаг (?i) в начале делает поиск нечувствительным к регистру.
ШаблонПоиска = "(?i)(?:г|с|пгт|д|пос)\.\s*([А-ЯЁа-яё\s\-]+)";
// Проверим на разных строках
ВывестиРезультатДляСтроки(НаименованиеОфиса1, ШаблонПоиска);
ВывестиРезультатДляСтроки(НаименованиеОфиса2, ШаблонПоиска);
ВывестиРезультатДляСтроки(НаименованиеОфиса3, ШаблонПоиска);
ВывестиРезультатДляСтроки(НаименованиеОфиса4, ШаблонПоиска);
КонецПроцедуры
Процедура ВывестиРезультатДляСтроки(СтрокаАдреса, Шаблон)
РезультатПоиска = СтрНайтиПоРегулярномуВыражению(СтрокаАдреса, Шаблон);
Если РезультатПоиска <> Неопределено Тогда
// Группа с индексом 0 - это все найденное совпадение (например, "г. Москва").
// Группа с индексом 1 - это то, что попало в первые скобки в шаблоне (например, "Москва").
НайденныйГород = СокрЛП(РезультатПоиска.ПолучитьГруппу(1));
Сообщить("В строке """ + СтрокаАдреса + """ найден населенный пункт: " + НайденныйГород);
Иначе
Сообщить("В строке """ + СтрокаАдреса + """ населенный пункт не найден по шаблону.");
КонецЕсли;
КонецПроцедуры
Этот подход уже более гибок, но он все равно неидеален. Что если в названии города будет запятая? Или пользователь вообще не укажет префикс? Разбор произвольного текста всегда будет полон "сюрпризов".
Как справедливо отмечают опытные разработчики, парсинг адресов произвольного формата — это "зло". Пытаться предусмотреть все возможные варианты ввода — это хрупкое и неблагодарное занятие. Вместо того чтобы "разгадывать" то, что ввел пользователь, правильнее всего обеспечить ввод данных в структурированном виде. Рассмотрим профессиональные подходы.
В большинстве типовых конфигураций 1С есть БСП, которая включает подсистему «Контактная информация». Она предоставляет готовые механизмы для хранения адресов в структурированном виде, с разделением на поля: страна, регион, город, улица, дом и т.д. Данные при этом привязываются к официальному адресному классификатору (ФИАС/ГАР).
Преимущества:
Вместо того чтобы давать пользователю обычное текстовое поле для ввода адреса, используйте стандартные формы выбора адреса из классификатора. Платформа 1С предоставляет удобные диалоги, которые позволяют пользователю по частям выбрать нужный адрес. Таким образом, вы гарантируете, что в систему попадут корректные и уже структурированные данные.
Если у вас уже есть большая база данных с "грязными" адресами, которые нужно разобрать, лучшим решением будет использование специализированных внешних сервисов (например, DaData). Такие сервисы:
Это самый надежный способ автоматической обработки уже накопленных неструктурированных данных.
Вывод: регулярные выражения — мощный инструмент, но он подходит для простых и строго формализованных задач. Когда речь идет о таких сложных и вариативных данных, как адреса, основной стратегией должно быть не "разгадывание" строки, а принудительное структурирование данных на этапе их ввода. Используйте возможности БСП и штатные формы 1С, чтобы обеспечить чистоту и порядок в ваших данных.