При разработке механизмов обмена данными или обработке текстовых логов программисты 1С часто сталкиваются с необходимостью извлечь конкретные значения из строк со сложной структурой. В этой статье мы подробно разберем, как с помощью регулярных выражений получить идентификаторы, текстовые описания и опциональные коды из строки формата * SOL:1201 тут слова строки текста , EXPOZITIE SТ *.
Представим, что нам нужно разобрать строку и поместить данные в следующие переменные:
Проанализируем ситуацию: использование стандартных функций работы со строками, таких как СтрНайти() или Сред(), может быть избыточно сложным из-за переменной длины текста и наличия необязательных элементов. Регулярные выражения позволяют решить эту задачу одной операцией поиска.
Долгое время в 1С единственным способом работы с регулярными выражениями было использование COM-объекта. Этот метод до сих пор актуален для старых версий платформы и обычных форм. Рассмотрим код, который создает объект и настраивает его для поиска.
// Создаем объект регулярного выражения
RegExp = Новый COMОбъект("VBScript.RegExp");
RegExp.IgnoreCase = Истина; // Игнорировать регистр
RegExp.Global = Ложь; // Нам нужно только первое совпадение
RegExp.MultiLine = Ложь; // Обрабатываем одну строку
// Устанавливаем паттерн
RegExp.Pattern = "SOL:(\d{4})(?:-\s*(\d{4}))?\s+(.*?)\s*,\s*EXPOZITIE\s*([A-Z]{1,2})?";
Разберем, что означает этот паттерн по шагам:
SOL:(\d{4}) — ищем подстроку "SOL:", после которой идут ровно 4 цифры. Скобки создают захватывающую группу, чтобы мы могли вытащить это число.(?:-\s*(\d{4}))? — эта часть отвечает за диапазон. (?:...) — незахватывающая группа для группировки символов тире и цифр. Знак ? в конце делает всю группу необязательной. Внутри нее (\d{4}) — это вторая захватывающая группа для второго числа.\s+(.*?)\s*, — ищем текст. .*? означает "любые символы в минимальном количестве" (ленивый поиск), пока не встретим запятую. Это позволяет нам корректно захватить "тут слова строки текста".EXPOZITIE\s*([A-Z]{1,2})? — ищем ключевое слово и опционально захватываем 1 или 2 буквы латиницы.После выполнения поиска нам нужно обратиться к коллекции SubMatches, где хранятся наши группы захвата. Посмотрим на пример обработки результата:
ТекстИсточник = "* SOL:1201-1500 тут слова строки текста , EXPOZITIE ST *";
Matches = RegExp.Execute(ТекстИсточник);
Если Matches.Count > 0 Тогда
Match = Matches.Item(0);
// Индексация SubMatches начинается с 0
SOL = Match.SubMatches(0); // "1201"
SOL2 = Match.SubMatches(1); // "1500" или пустая строка
СтрТХТ = СокрЛП(Match.SubMatches(2)); // "тут слова строки текста"
EXPOZITIE = Match.SubMatches(3); // "ST"
// Дополнительная проверка для SOL2
Если ПустаяСтрока(SOL2) Тогда
SOL2 = SOL;
КонецЕсли;
КонецЕсли;
Если вы работаете на современной платформе (начиная с версии 8.3.24), рекомендуется использовать встроенные классы РегулярноеВыражение. Это работает быстрее, стабильнее на Linux и не требует COM-соединения. Проанализируем, как изменится наш код.
// В нативном 1С синтаксис немного отличается
Паттерн = "SOL:(\d{4})(?:-\s*(\d{4}))?\s+(.*?)\s*,\s*EXPOZITIE\s*([A-Z]{1,2})?";
РегВыр = Новый РегулярноеВыражение(Паттерн);
Результат = РегВыр.Найти(ТекстИсточник);
Если Результат <> Неопределено Тогда
// Группы доступны через метод Группы.Получить()
SOL = Результат.Группы.Получить(1).Значение;
// Обратите внимание, что в нативном 1С индекс 0 - это вся найденная строка,
// а индексы 1, 2... - это захватывающие группы.
SOL2 = ?(Результат.Группы.Количество() > 2, Результат.Группы.Получить(2).Значение, "");
СтрТХТ = СокрЛП(Результат.Группы.Получить(3).Значение);
Если Результат.Группы.Количество() > 4 Тогда
EXPOZITIE = Результат.Группы.Получить(4).Значение;
КонецЕсли;
КонецЕсли;
Как справедливо заметили некоторые участники обсуждения, в простых случаях можно обойтись без регулярных выражений, используя метод СтрРазделить(). Это может быть полезно, если структура строки гарантированно стабильна. Выясним причину, почему это иногда удобнее: такой код легче читать разработчикам, не знакомым с синтаксисом Regex.
EXPOZITIE.СокрЛП() для очистки лишних пробелов.
ЧастиСтроки = СтрРазделить(ТекстИсточник, ",");
Если ЧастиСтроки.Количество() >= 2 Тогда
// Обработка левой части (SOL и текст)
ЛеваяЧасть = СтрЗаменить(ЧастиСтроки[0], "*", "");
// Далее логика поиска двоеточия и пробелов...
// Обработка правой части (EXPOZITIE)
ПраваяЧасть = СтрЗаменить(ЧастиСтроки[1], "*", "");
Если СтрНайти(ПраваяЧасть, "EXPOZITIE") > 0 Тогда
EXPOZITIE = СокрЛП(СтрЗаменить(ПраваяЧасть, "EXPOZITIE", ""));
КонецЕсли;
КонецЕсли;
1. Работа с кириллицей. Если в паттерне вы используете \w, помните, что в реализации VBScript.RegExp этот класс символов может не включать русские буквы. Для надежности используйте . (любой символ) или явно указывайте диапазоны [а-яА-ЯёЁ].
2. Ленивые квантификаторы. Использование .*? вместо .* критически важно, когда в строке может быть несколько запятых. Ленивый квантификатор заставит регулярку остановиться на ближайшей запятой, а не поглощать текст до самого конца строки.
3. Проверка на пустые значения. Всегда проверяйте результат работы регулярного выражения. Если группа опциональна (как наш EXPOZITIE), метод SubMatches вернет пустую строку, а в нативном 1С группа может иметь пустое свойство Значение. Проанализируем это в коде, чтобы избежать ошибок рантайма.
Рассмотренные нами методы позволяют гибко настраивать парсинг строк под любые нужды. Регулярные выражения — это мощный инструмент, который при правильном подходе экономит десятки строк кода и делает обработку данных более надежной.