Как разобрать сложную строку наименования номенклатуры в 1С при помощи регулярных выражений и строковых функций?

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

В процессе интеграции информационных систем, загрузки прайс-листов поставщиков или наведения порядка в справочнике Номенклатура разработчики 1С часто сталкиваются с необходимостью разбора сложных маркировок. Например, нам нужно разложить строку наименования вида Гильза ГЦР.103-М20х1,5-М20х1,5-10/8-120-6.3 на составляющие технические свойства: тип изделия, диаметр, шаг резьбы, длина, марка стали и другие параметры.

Ситуация осложняется тем, что в базе данных за годы ведения учета накапливаются разные варианты написания одного и того же шаблона: где-то разделителем служит дефис, где-то точка или пробел, а некоторые необязательные показатели могут и вовсе отсутствовать. В этой статье мы подробно разберем, как решать подобные задачи парсинга строк как на старых платформах семейства 1С:Предприятие 8.2, так и на современных версиях 1С:Предприятия 8.3 с использованием встроенных механизмов.

---

Метод 1. Использование встроенных строковых функций (подход для простых строк)

Если структура строки относительно однородна и количество разделителей фиксировано, мы можем обойтись классическими функциями работы со строками. Это наиболее производительный метод, который работает абсолютно на любой версии платформы 1С и не требует сторонних библиотек.

Рассмотрим традиционный трюк с заменой символов-разделителей на символы перевода строки. Это позволяет быстро превратить исходный текст в многострочную строку и извлекать нужные параметры по индексам строк.

Давайте проанализируем пример кода, реализующий этот алгоритм:


// Исходная строка для разбора
ИсходнаяСтрока = "Гильза ГЦР.103-М20х1,5-М20х1,5-10/8-120-6.3";

// Заменяем основной разделитель (дефис) на перевод строки
МногострочныйТекст = СтрЗаменить(ИсходнаяСтрока, "-", Символы.ПС);

// Теперь мы можем получить каждую подстроку по её номеру
КоличествоСтрок = СтрЧислоСтрок(МногострочныйТекст);

Если КоличествоСтрок >= 6 Тогда
    Параметр1 = СтрПолучитьСтроку(МногострочныйТекст, 1); // "Гильза ГЦР.103"
    Параметр2 = СтрПолучитьСтроку(МногострочныйТекст, 2); // "М20х1,5"
    Параметр3 = СтрПолучитьСтроку(МногострочныйТекст, 3); // "М20х1,5"
    Параметр4 = СтрПолучитьСтроку(МногострочныйТекст, 4); // "10/8"
    Параметр5 = СтрПолучитьСтроку(МногострочныйТекст, 5); // "120"
    Параметр6 = СтрПолучитьСтроку(МногострочныйТекст, 6); // "6.3"
    
    // Выполняем дальнейшую обработку выделенных параметров
КонецЕсли;

Если ваша платформа обновлена до версии 8.3.6 и выше, мы рекомендуем использовать более изящную встроенную функцию СтрРазделить(), которая возвращает готовый массив подстрок:


ИсходнаяСтрока = "Гильза ГЦР.103-М20х1,5-М20х1,5-10/8-120-6.3";
// Разделяем строку по дефису, игнорируя пустые значения
МассивПараметров = СтрРазделить(ИсходнаяСтрока, "-", Ложь);

Если МассивПараметров.Количество() >= 6 Тогда
    ТипИзделия = МассивПараметров[0]; // Индексация массива начинается с 0
    ПерваяРезьба = МассивПараметров[1];
    ВтораяРезьба = МассивПараметров[2];
    ДиаметрВнутренний = МассивПараметров[3];
    Длина = МассивПараметров[4];
    ВидСтали = МассивПараметров[5];
КонецЕсли;

Плюсы метода: максимальная скорость работы, простота чтения кода, кроссплатформенность (работает на Windows и Linux серверах без сбоев).

Минусы метода: если один из параметров в середине строки отсутствует, вся цепочка индексов сдвигается, и мы получаем неверные данные. Этот метод не подходит для разбора маркировок с динамической структурой.

---

Метод 2. Регулярные выражения через COM-объект VBScript.RegExp (для платформы 1С 8.2)

Когда наименования содержат вариации написания (пробелы вместо точек, опциональные параметры), строковые функции становятся громоздкими. На старых версиях платформы 1С (до релиза 8.3.23), включая классическую 1С:Предприятие 8.2, единственным полноценным способом работы с регулярными выражениями было использование встроенного Windows-компонента VBScript.RegExp через механизм COM-соединения.

Выясним по шагам, как настроить парсинг с помощью этого COM-объекта:

  1. Создаем экземпляр COM-объекта VBScript.RegExp.
  2. Задаем свойства поиска: признак глобальности Global, игнорирование регистра символов IgnoreCase.
  3. Определяем шаблон регулярного выражения Pattern с группами захвата (круглые скобки ()), которые позволят вытащить конкретные значения из текста.
  4. Вызываем метод Execute() для поиска соответствий.

Посмотрим на практическую реализацию этого подхода:


Функция РазобратьНаименованиеЧерезCOM(Знач ИсходныйТекст) Экспорт

    РезультатРазбора = Новый Структура("Успех, Диаметр, Резьба, Длина, Сталь", Ложь, "", "", "", "");

    Попытка
        RegExp = Новый COMОбъект("VBScript.RegExp");
    Исключение
        ЗаписьЖурналаРегистрации("РазборНоменклатуры", УровеньЖурналаРегистрации.Ошибка,,, 
            "Не удалось запустить VBScript.RegExp на текущем компьютере!");
        Возврат РезультатРазбора;
    КонецПопытки;

    // Настраиваем параметры регулярного выражения
    RegExp.IgnoreCase = Истина;
    RegExp.Global = Ложь; // Нам нужно только первое полное совпадение шаблона
    
    // Описываем шаблон. Выделяем группы захвата круглыми скобками:
    // Группа 1: Диаметр после "ГЦР." (цифры)
    // Группа 2: Первая резьба (символ М, цифры, х, цифры)
    // Группа 3: Длина (цифры)
    RegExp.Pattern = "ГЦР\.(\d+)-(М\d+х\d+(?:,\d+)?).*-(\d+)-([\d.]+)";

    Если RegExp.Test(ИсходныйТекст) Тогда
        Matches = RegExp.Execute(ИсходныйТекст);
        Если Matches.Count > 0 Тогда
            Match = Matches.Item(0);
            
            // Заполняем структуру из групп захвата (SubMatches)
            РезультатРазбора.Диаметр = Match.SubMatches.Item(0);
            РезультатРазбора.Резьба   = Match.SubMatches.Item(1);
            РезультатРазбора.Длина    = Match.SubMatches.Item(2);
            РезультатРазбора.Сталь    = Match.SubMatches.Item(3);
            РезультатРазбора.Успех    = Истина;
        КонецЕсли;
    КонецЕсли;

    Возврат РезультатРазбора;

КонецФункции

Важное ограничение: данный COM-объект будет успешно работать только под управлением операционной системы семейства Windows. Если код выполняется на стороне сервера 1С под управлением ОС Linux, вызов Новый COMОбъект("VBScript.RegExp") завершится критической ошибкой. В таком случае приходится искать обходные кроссплатформенные пути или выполнять разбор исключительно на клиентском приложении под управлением Windows.

---

Метод 3. Кроссплатформенный трюк через схемы XDTO (для старых версий 1С на Linux)

Что делать, если база данных работает на Linux-сервере под управлением старой платформы 1С 8.2 или 8.3 (до версии 8.3.23), где нет встроенной поддержки регулярных выражений? Разработчики нашли крайне оригинальный и элегантный обходной путь через использование фабрики XDTO.

В стандартах XML Schema (на которых базируется XDTO в 1С) предусмотрена возможность наложения ограничений на текстовые типы данных с использованием тега <pattern>. Схема XDTO обрабатывается платформой нативно на любом сервере (включая Linux). Мы можем динамически генерировать схему XML с нужным регулярным выражением, импортировать её в фабрику XDTO и проверять строки на валидность.

Рассмотрим, как устроен этот механизм на практике:


Функция ПроверитьСтрокуПоРегулярномуВыражениюXDTO(Знач ПроверяемаяСтрока, Знач ШаблонРегулярки) Экспорт

    // Создаем XML-схему во временном файле во встроенной памяти
    ИмяФайлаСхемы = ПолучитьИмяВременногоФайла("xsd");
    
    ЗаписьXML = Новый ЗаписьXML;
    ЗаписьXML.ОткрытьФайл(ИмяФайлаСхемы);
    ЗаписьXML.ЗаписатьОбъявлениеXML();
    
    // Формируем структуру схемы с ограничением "pattern"
    ЗаписьXML.ЗаписатьНачалоЭлемента("xs:schema", "http://www.w3.org/2001/XMLSchema");
    ЗаписьXML.ЗаписатьАтрибут("targetNamespace", "http://www.v8.1c.ru/regex");
    ЗаписьXML.ЗаписатьАтрибут("xmlns:xs", "http://www.w3.org/2001/XMLSchema");
    ЗаписьXML.ЗаписатьАтрибут("xmlns:tns", "http://www.v8.1c.ru/regex");
    
    ЗаписьXML.ЗаписатьНачалоЭлемента("xs:simpleType");
    ЗаписьXML.ЗаписатьАтрибут("name", "RegexType");
    
    ЗаписьXML.ЗаписатьНачалоЭлемента("xs:restriction");
    ЗаписьXML.ЗаписатьАтрибут("base", "xs:string");
    
    ЗаписьXML.ЗаписатьНачалоЭлемента("xs:pattern");
    ЗаписьXML.ЗаписатьАтрибут("value", ШаблонРегулярки);
    ЗаписьXML.ЗаписатьКонецЭлемента(); // xs:pattern
    
    ЗаписьXML.ЗаписатьКонецЭлемента(); // xs:restriction
    ЗаписьXML.ЗаписатьКонецЭлемента(); // xs:simpleType
    ЗаписьXML.ЗаписатьКонецЭлемента(); // xs:schema
    ЗаписьXML.Закрыть();
    
    // Загружаем схему в фабрику XDTO
    Попытка
        МояФабрика = СоздатьФабрикуXDTO(ИмяФайлаСхемы);
        УдалитьФайлы(ИмяФайлаСхемы);
        
        // Пытаемся создать значение созданного типа данных
        ТипRegex = МояФабрика.Тип("http://www.v8.1c.ru/regex", "RegexType");
        ПроверяемоеЗначение = МояФабрика.Создать(ТипRegex, ПроверяемаяСтрока);
        
        // Если создание прошло без ошибок, строка соответствует регулярному выражению
        Возврат Истина;
    Исключение
        УдалитьФайлы(ИмяФайлаСхемы);
        Возврат Ложь; // Строка не подошла под регулярный шаблон
    КонецПопытки;

EndФункции

Обратите внимание: данный метод идеально подходит для проверки (валидации) строки на соответствие шаблону (например, корректен ли артикул или ИНН). Однако вытащить с его помощью подстроки (группы захвата) не удастся. Для извлечения отдельных параметров придется комбинировать проверку XDTO с функциями Сред() или СтрРазделить().

---

Метод 4. Родная поддержка регулярных выражений в современных версиях платформы (1С 8.3.23 и выше)

Начиная с версии платформы 8.3.23, фирма «1С» добавила полноценную встроенную поддержку регулярных выражений. Теперь разработчикам больше не требуются COM-объекты или XDTO-схемы. Поиск выполняется на уровне ядра платформы с использованием стандарта ICU (который базируется на привычном синтаксисе регулярных выражений Perl).

Для работы со строками в глобальный контекст были добавлены следующие новые функции:

Давайте подробно разберем на примере, как решить задачу из сообщения форума, используя современный платформенный функционал. Нам нужно извлечь из маркировки все параметры одним махом.


// Исходные данные
Маркировка = "Гильза ГЦР.103-М20х1,5-М20х1,5-10/8-120-6.3";

// Составим регулярное выражение. 
// Каждую нужную подстроку помещаем в круглые скобки - это наши группы захвата.
// \d+ означает последовательность цифр, [^-\s]+ означает любую последовательность символов кроме дефиса и пробела
ШаблонРегулярки = "^Гильза ГЦР\.(\d+)-([^-]+)-([^-]+)-([^-]+)-(\d+)-([\d.]+)$";

// Выполняем поиск совпадения
РезультатПоиска = СтрНайтиПоРегулярномуВыражению(Маркировка, ШаблонРегулярки);

// Проверяем, найдено ли соответствие шаблону
Если РезультатПоиска.НачальнаяПозиция > 0 Тогда
    
    // Получаем доступ к найденным подгруппам.
    // Метод ПолучитьПодгруппы() возвращает массив объектов РезультатПоискаПоРегулярномуВыражению
    Подгруппы = РезультатПоиска.ПолучитьПодгруппы();
    
    Если Подгруппы.Количество() = 6 Тогда
        
        // Извлекаем значения параметров по их координатам в исходной строке
        Диаметр    = Сред(Маркировка, Подгруппы[0].НачальнаяПозиция, Подгруппы[0].Длина); // "103"
        Резьба1    = Сред(Маркировка, Подгруппы[1].НачальнаяПозиция, Подгруппы[1].Длина); // "М20х1,5"
        Резьба2    = Сред(Маркировка, Подгруппы[2].НачальнаяПозиция, Подгруппы[2].Длина); // "М20х1,5"
        Размерность= Сред(Маркировка, Подгруппы[3].НачальнаяПозиция, Подгруппы[3].Длина); // "10/8"
        Длина      = Сред(Маркировка, Подгруппы[4].НачальнаяПозиция, Подгруппы[4].Длина); // "120"
        Сталь      = Сред(Маркировка, Подгруппы[5].НачальнаяПозиция, Подгруппы[5].Длина); // "6.3"
        
        // Записываем данные в свойства номенклатуры
        Сообщить("Успешно разобрано!");
        Сообщить("Диаметр: " + Диаметр + ", Резьба: " + Резьба1 + ", Сталь: " + Сталь);
        
    КонецЕсли;
    
Иначе
    Предупреждение("Наименование номенклатуры не соответствует стандартному шаблону!");
КонецЕсли;

Преимущества встроенного механизма 1С 8.3.23+:

  1. Высокая скорость работы: встроенный парсер работает до 10-20 раз быстрее, чем аналогичный COM-объект.
  2. Абсолютная кроссплатформенность: код будет одинаково быстро и без ошибок работать на Windows, Linux, macOS, на клиенте и на сервере 1С.
  3. Простота отладки: мы оперируем стандартными объектами 1С, результаты поиска легко просматривать в табло отладчика.

---

Нюанс работы с управляющими символами регулярных выражений в 1С

При переносе готовых паттернов регулярных выражений из интернет-конструкторов (таких как regexr.com или regex101.com) во встроенный язык 1С важно учитывать специфику работы с управляющими символами (например, знаками табуляции, переводами строк и кавычками).

Например, если ваш шаблон содержит символ двойной кавычки, во встроенном языке 1С его необходимо экранировать путем удваивания:


// Шаблон для поиска текста в кавычках: "текст"
Шаблон1С = """([^""]+)""";

Для поиска управляющих символов перевода строки рекомендуется предварительно заменять их на системные константы 1С:


// Очищаем строку от лишних символов возврата каретки перед анализом
ОчищеннаяСтрока = СтрЗаменить(ИсходнаяСтрока, Символы.ВК, "");

Используйте интерактивные визуальные конструкторы регулярных выражений для 1С (например, разработки на платформе Infostart или компоненты инструментов разработчика TSD), которые позволяют проверить работу составленных шаблонов прямо на ваших реальных данных перед внедрением программного кода в конфигурацию.

← На главную