Как обрезать строку справа по скобкам в 1С 8.2 с учетом вложенности

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

При работе со справочниками номенклатуры, особенно в фармацевтической или технической отраслях, часто возникает задача очистки наименования от дополнительной информации, указанной в конце строки в скобках. Например, когда нужно превратить «Авелокс (Bayer AG (рецепт.))» в просто «Авелокс». Сложность заключается в том, что внутри основных скобок могут находиться вложенные, а сама платформа 1С 8.2 имеет ограниченный набор строковых функций по сравнению с современными версиями 8.3.

В этой статье мы подробно разберем, как реализовать надежный алгоритм обрезки строки, который корректно обрабатывает вложенные структуры и учитывает специфику платформы 8.2.

Анализ ограничений платформы 1С 8.2

Прежде чем переходить к коду, проанализируем инструменты, которые нам доступны. В старых версиях платформы (8.2 и ранние релизы 8.3):

  1. Отсутствует функция СтрНайти, позволяющая искать символы с конца строки.
  2. Отсутствует функция СтрРазделить, которая могла бы разбить строку в массив по разделителю.
  3. Метод СтрЗаменить не позволяет ограничивать количество замен.

Поэтому стандартный подход через поиск позиции символа ( слева направо не сработает для строк вида «Амлотоп №30 (амлодипин) (Нижфарм ОАО)», так как нам нужно сохранить информацию о веществе, но удалить производителя.

Решение 1: Алгоритм баланса скобок (обход с конца)

Рассмотрим наиболее производительный и логически верный метод — обход строки справа налево с использованием счетчика «баланса». Суть метода заключается в том, что мы идем от последнего символа к первому и ищем ту открывающую скобку, которая закрывает всю конечную конструкцию.

Разберем алгоритм по шагам:

  1. Очистим строку от лишних пробелов справа с помощью СокрП.
  2. Заведем переменную-счетчик, которая будет увеличиваться при встрече закрывающей скобки ) и уменьшаться при встрече открывающей (.
  3. Как только счетчик станет равным нулю после уменьшения, мы нашли позицию «той самой» открывающей скобки.

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


Функция ОбрезатьСкобкиСправа(Знач ИсходнаяСтрока) Экспорт
    
    ИсходнаяСтрока = СокрП(ИсходнаяСтрока);
    ДлинаСтроки = СтрДлина(ИсходнаяСтрока);
    
    // Проверим, заканчивается ли вообще строка на скобку
    Если Прав(ИсходнаяСтрока, 1) <> ")" Тогда
        Возврат ИсходнаяСтрока;
    КонецЕсли;
    
    СчетчикБаланса = 0;
    ПозицияОбрезания = 0;
    
    // Цикл с конца строки к началу
    Для НомерСимвола = -ДлинаСтроки По -1 Цикл
        
        Индекс = -НомерСимвола; // Получаем текущий индекс символа
        Символ = Сред(ИсходнаяСтрока, Индекс, 1);
        
        Если Символ = ")" Тогда
            СчетчикБаланса = СчетчикБаланса + 1;
        ИначеЕсли Символ = "(" Тогда
            СчетчикБаланса = СчетчикБаланса - 1;
        КонецЕсли;
        
        // Если баланс сошелся в ноль, значит нашли начало закрывающей группы
        Если СчетчикБаланса = 0 Тогда
            ПозицияОбрезания = Индекс;
            Прервать;
        КонецЕсли;
        
    КонецЦикла;
    
    Если ПозицияОбрезания > 0 Тогда
        // Обрезаем строку и удаляем возможный пробел перед скобкой
        Возврат СокрП(Лев(ИсходнаяСтрока, ПозицияОбрезания - 1));
    Иначе
        Возврат ИсходнаяСтрока;
    КонецЕсли;
    
КонецФункции

Проанализируем ситуацию: в примере «Авелокс (Bayer AG (рецепт.))» цикл встретит первую закрывающую скобку (баланс = 1), затем вторую (баланс = 2), затем встретит открывающую у слова «рецепт.» (баланс = 1) и, наконец, встретит открывающую перед «Bayer» (баланс = 0). В этот момент переменная ПозицияОбрезания зафиксирует начало всей конструкции, и мы корректно получим результат.

Решение 2: Использование регулярных выражений через COM

Если нам нужно более гибкое решение (например, удалять только если в скобках есть определенные слова), мы можем воспользоваться объектом VBScript.RegExp. Несмотря на то, что это внешнее обращение к Windows API, оно работает крайне быстро и эффективно в 1С 8.2.

Рассмотрим пример кода:


Функция УдалитьПоследниеСкобкиРегуляркой(ИсходнаяСтрока)
    
    RegExp = Новый COMОбъект("VBScript.RegExp");
    RegExp.IgnoreCase = Истина;
    RegExp.Global = Ложь; // Нам нужно только последнее вхождение
    
    // Паттерн ищет пробел, затем открывающую скобку, 
    // любые символы внутри (включая вложенные скобки) и закрывающую скобку в конце строки
    RegExp.Pattern = "\s*\([^)]*(\([^)]*\)[^)]*)*\)$";
    
    Результат = RegExp.Replace(СокрП(ИсходнаяСтрока), "");
    
    Возврат Результат;
    
КонецФункции

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

Решение 3: Запросный метод (SQL)

В некоторых случаях, когда требуется обработать сразу тысячи строк (например, при загрузке прайс-листа), может быть полезен метод обработки через временные таблицы в запросе. Выясним причину, почему это иногда предпочтительнее: SQL сервер обрабатывает строковые операции на своей стороне быстрее, чем интерпретатор 1С в цикле перебора объектов.

Как мы видели в обсуждении, можно построить запрос, который через ПОДСТРОКА анализирует символы. Однако стоит признать, что для 1С 8.2 такой запрос получается крайне громоздким (как в сообщении 16) из-за необходимости эмулировать индексы символов через соединение с таблицей чисел. Мы рекомендуем использовать этот метод только в исключительных случаях, когда работа со строками в коде становится «узким местом» производительности.

Практические советы по работе со справочниками

Проанализируем дополнительные нюансы, которые могут возникнуть при использовании данных алгоритмов:

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

← На главную