Найти в наименовании цвет и размер с помощью регулярных выражений. Розница 2.3

У клиента поставщик присылает накладные, где в наименовании товара содержится размер и цвет, а в Рознице при загрузке нужно выделять размер и цвет в отдельные колонки.

В своей жизни я написал уже очень много разборов строк, поэтому решил на этот раз попробовать воспользоваться регулярными выражениям с помощью COM-объекта RegExp.

Открыл онлайн-тестер регулярных выражений regex101.com, почитал шпаргалку и попробовал разобрать наименование «Ботинки (р.16,черный)» с помощью выражения:

\(.+,.+\)

Система выдала, что соответствие найдено:

Но ведь мне нужно было выделить размер и цвет отдельно. Немного почитав документацию, я нашел, как выделять части выражения submatches (группы), получилось выражение:

\((.+),(.+)\)

Пришлось немного поковыряться в интернете, чтобы найти, как не просто проверять на соответствие шаблону, но выделять submatches, в итоге получился код:

RegExp = Новый COMОбъект(«VBScript.RegExp»);// создаем объект для работы с регулярными выражениями
RegExp.MultiLine = Истина;  // истина — текст многострочный, ложь — одна строка
RegExp.Global = Истина;     // истина — поиск по всей строке, ложь — до первого совпадения
RegExp.IgnoreCase = Истина; // истина — игнорировать регистр строки при поиске

ТекНаименование = …;



//Шаблон = «\((.+),(.+)\)»; //не срабатывает
Шаблон = «\(([^\)]+),(.+)\)»;

RegExp.Pattern = Шаблон;    // шаблон (регулярное выражение)


Соответствия = RegExp.Execute(ТекНаименование);
Всего = Соответствия.Count;
//Сообщить(«» + ТекНаименование + «: » + Всего);

Если Соответствия.Count >= 1 Тогда
   
// + » » + Токены.Item(0).SubMatches.Item(0));
   
Соо = Соответствия.Item(Всего 1).Submatches; //Последний
   
ТекРазмер = СокрЛП(Соо.Item(0));
   
ТекЦвет = СокрЛП(Соо.Item(1));
КонецЕсли;

Но увы, оно не работало на наименованиях вида «Ботинки (детские) (р.16,черный)», т.е. там где было много скобок. Пришлось поправить шаблон на такой:

\(([^\)]+),(.+)\)

Победив подобные наименования, я внезапно столкнулся с еще одним видом наименований:

«Ботинки (детские,девичьи) (р.16,черный)»

Тут уж я спасовал и воспользовался «костылем» на языке 1С в виде выделения последней открывающей скобки:

ПозСкобки = СтрНайти(ТекНаименование, «(«, НаправлениеПоиска.СКонца);
Если
ПозСкобки = 0 Тогда
    Возврат;
//Там где скобок нет, не обрабатываем
КонецЕсли;
ТекНаименование = Сред(ТекНаименование, ПозСкобки);

Даже не знаю, как правильно выделить последний шаблон. Знаете?

Я попробовал поиграть с кванторами «жадности», но не помогало.

Но так или иначе, я набил руку в регулярных выражениях, правда, нужно немного подучить теорию регулярных выражений.

Время факт: 1 час.

fixin

Программирую на 1С с 1999 года. В 1С просто Гений. В 2020 году ушел из офиса на вольные хлеба фриланса. Принимаю заказы.

Читайте также:

комментариев 14

  1. bob32:

    Теория регулярных выражений где-то на 1-м курсе учится в курсах по формальным грамматикам.

    Самое главное понимать что можно разобрать регуляркой а что нет. Когда синтаксис под регулярные выражения не подпадает то используется LL/LR разбор, а регулярка юзается для разбивки на токены.

    Так же стоит помнить, что регулярное выражение можно сгенерить, чтоб не писать руками. Если у нас фиксированные варианты наимнований и они в справочнике то можно сгенерить regex по данным.

    А в целом в регулярках ничего сложного. Сидел бы в консоле под линухом, давно бы пользовался (find/grep/awk/sed)

    • fajij28770:

      > Сидел бы в консоле под линухом, давно бы пользовался
      в винде уже давно есть аналоги — powershell gci + select-string
      да и за пределами шеллов постоянно возникает потребность что-то заматчить регэксапми. короче, я хз как он 20 лет в профессии без регэкспов жил, страшно представить, сколько разборов строк он написал руками

      • В 1С редко встречается необходимость в сложном разборе строк.
        А RegExp не встроен в платформу 1С, поэтому все же это внешний инструмент.

        • fajij28770:

          хз причем тут 1с, но у меня и месяца не бывает, что я регэкспами не пользовался. если и не по рабочим задачам, то для автоматизации каких-нибудь рутинных операций.

          • видимо, ты решаешь другие задачи. У нас в 1С сложная обработка строк требуется крайне редко. Обычно вот в таких вот неформализованных задачах.
            Потому что там где формализованно, регэкспы не нужны.

    • Платформа 1С не поддерживает Reg Exp. Приходится использовать внешние инструменты. Наверное, не считает важным.

      • bob32:

        Жаль. Это полезный инструмент который нужен при работе с текстом. Почти во всех языка есть поддержка в стандартных библиотеках. Тут 1С пинать надо, странно что не запинали. Помимо поиска regex-ы еще позволяют делать замену что так же удобно.

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

        • да, но в моей практике обрабатывать текст приходилось крайне редко. Поэтому в 1С регулярные выражения и не встроены в платформу.
          Обычно данные уже формализованы. Сырые тексты редко приходится обрабатывать.

  2. fajij28770:

    ну так и заматчился бы на размер \(р\.(d+),(.+?)\)

      • fajij28770:

        тебе же надо только скобки с размером и цветом сматчить, вот тут р\.\d+ и отбросит все лишние совпадения.
        да там еще много как можно было бы сделать: \((.+?),(.+?)\) и брать всегда последнее совпадение в строке (при условии что у тебя не больше одного наименования в строке), или опциональный скобки заматчить (?:\(.*?\) )?\((.+?),(.+?)\), или negaitve lookbehind заиспользовать.

        • попробую это как-нибудь разобрать на досуге, но пока я решил проще — нахожу последнюю открывающую скобку и от нее пляшу.

  3. Zuko:

    Как идея к решению — заменить точку (произвольный символ) на символ кроме … (например кроме открывающейся скобки)

    Первый элемент должен содержать число

Добавить комментарий для fajij28770 Отменить ответ

Ваш адрес email не будет опубликован. Обязательные поля помечены *