В практике разработки на платформе 1С:Предприятие часто возникает задача предварительной обработки текстовых данных. Типичный пример — необходимость обрезать технические суффиксы, лишние знаки или числовые коды в конце наименования товаров при выводе их в печатные формы (макеты) или при выгрузке во внешние системы. Например, когда в справочнике хранится наименование "Продукция 21", а в макете необходимо вывести просто "Продукция".
В рамках этой статьи мы подробно разберем, как решить эту задачу. Мы проанализируем классические строковые функции платформы, укажем на критические ошибки популярных форумных решений, а также рассмотрим современные и наиболее эффективные подходы с использованием регулярных выражений и встроенных модулей Библиотеки Стандартных Подсистем (БСП).
Это самый популярный и простой способ, который работает на абсолютно любой версии платформы 1С:Предприятие (включая старые релизы 7.7 и 8.0). Он идеально подходит, если вам нужно строго отсечь ровно два последних символа от строки.
Рассмотрим пример реализации этого алгоритма:
// Очищаем строку от случайных пробелов на концах
НаименованиеОчищенное = СокрЛП(Номенклатура.Наименование);
ДлинаСтроки = СтрДлина(НаименованиеОчищенное);
Если ДлинаСтроки > 2 Тогда
Результат = Лев(НаименованиеОчищенное, ДлинаСтроки - 2);
Иначе
Результат = ""; // Если строка изначально была слишком короткой
КонецЕсли;
Разберем по шагам, как работает данный код:
СокрЛП(). Это критически важно! Если в конце строки будут находиться невидимые символы пробела (например, "Товар "), функция без предварительной очистки отрежет именно эти пробелы, оставив значащие символы нетронутыми.СтрДлина() мы вычисляем общее количество символов в строке.Если ДлинаСтроки > 2. Если этого не сделать, и в функцию Лев() передать отрицательное число в качестве второго параметра, система вызовет ошибку времени выполнения (Run-time error).Лев() возвращает указанное количество символов с левой стороны строки.Альтернативный классический вариант — использование встроенной функции Сред(). По своей логике он аналогичен первому методу, но некоторым разработчикам такой синтаксис кажется более лаконичным:
НаименованиеОчищенное = СокрЛП(Номенклатура.Наименование);
ДлинаСтроки = СтрДлина(НаименованиеОчищенное);
Если ДлинаСтроки > 2 Тогда
Результат = Сред(НаименованиеОчищенное, 1, ДлинаСтроки - 2);
Иначе
Результат = "";
КонецЕсли;
Функция Сред() принимает три параметра: исходную строку, начальную позицию (в нашем случае это первый символ — 1) и длину вырезаемого фрагмента. Результат работы данного кода будет абсолютно идентичен первому способу.
Начинающие программисты часто пытаются применить функцию СтрЗаменить() для удаления символов с конца строки. Рассмотрим пример опасного кода, который часто предлагают на форумах:
// ВНИМАНИЕ: Опасный код с багом!
Результат = СтрЗаменить(Наименование, Прав(Наименование, 2), "");
Проанализируем ситуацию и выясним, почему этот код категорически нельзя использовать в реальных базах данных. Функция Прав(Наименование, 2) действительно возвращает последние два символа. Однако функция СтрЗаменить() заменяет все вхождения этой подстроки во всей строке, а не только в конце!
Рассмотрим живой пример:
СтрЗаменить("Штукатурка", "ка", ""), система заменит "ка" как в конце слова, так и в его середине (в слоге "-ка-").Еще одна грубая ошибка — последовательная замена цифр (попытка удалить числовой суффикс через массовую замену символов от "0" до "9"):
// ВНИМАНИЕ: Крайне неэффективный и опасный код!
Результат = СтрЗаменить(Наименование, "1", "");
Результат = СтрЗаменить(Результат, "2", ""); // и так далее до 0...
Этот подход полностью разрушит наименования, содержащие важные цифры внутри текста. Например, номенклатура "Кабель 3х1.5 мм 21" превратится в бесполезную строку "Кабель х. мм ". Кроме того, совершать 10 тяжелых вызовов строковых функций для обработки одной записи — это крайне неоптимально с точки зрения производительности.
Вернемся к задаче автора: убрать цифры и возможные пробелы только в конце наименования (например, преобразовать "Продукция 21" или "Продукция 21 " в "Продукция"). Если вы работаете на платформе ниже версии 8.3.23, наиболее надежным решением будет обход строки с конца в цикле.
Разберем по шагам готовую функцию, которая решает эту задачу:
Функция ПолучитьНаименованиеБезЧисловогоСуффикса(Знач ИсходноеНаименование) Экспорт
Длина = СтрДлина(ИсходноеНаименование);
НоваяДлина = Длина;
// Перебираем строку с конца к началу
Для НомерСимвола = -Длина По -1 Цикл
ИндексСимвола = -НомерСимвола;
КодТекущегоСимвола = КодСимвола(Сред(ИсходноеНаименование, ИндексСимвола, 1));
// КодСимвола = 32 (пробел)
// КодыСимволов от 48 до 57 (цифры от 0 до 9)
Если КодТекущегоСимвола = 32 Или (КодТекущегоСимвола >= 48 И КодТекущегоСимвола <= 57) Тогда
НоваяДлина = НоваяДлина - 1;
Иначе
Прервать; // Как только встретили букву, останавливаемся
КонецЕсли;
КонецЦикла;
Возврат Лев(ИсходноеНаименование, НоваяДлина);
КонецФункции
Этот алгоритм гарантирует полную безопасность данных: любые цифры, находящиеся внутри названия товара, останутся нетронутыми, а все лишние символы (пробелы и цифры) на конце будут аккуратно отсечены.
Начиная с версии платформы 8.3.23, в 1С появилась встроенная нативная поддержка регулярных выражений (RegExp). Теперь сложные циклы и посимвольный анализ больше не нужны. Регулярные выражения работают на уровне ядра платформы, выполняются мгновенно и кроссплатформенно (как на Windows, так и на Linux-серверах).
Для нашей задачи регулярные выражения подходят идеально.
Вариант А: Отрезать ровно 2 последних символа
// Шаблон "..$" означает любые два символа в самом конце строки
Результат = СтрЗаменитьПоРегулярномуВыражению(Номенклатура.Наименование, "..$", "");
Вариант Б: Удалить любые цифры и пробелы строго в конце строки
// Шаблон "[\s\d]+$" находит любые комбинации цифр (\d) и пробелов (\s) в конце строки ($)
Результат = СтрЗаменитьПоРегулярномуВыражению(Номенклатура.Наименование, "[\s\d]+$", "");
Этот способ является наиболее приоритетным и современным для всех конфигураций, работающих на актуальных версиях платформы 1С.
Если вы разрабатываете решение в среде типовой конфигурации (например, 1С:Управление торговлей, 1С:ERP, Бухгалтерия предприятия), то в вашем распоряжении по умолчанию есть Библиотека Стандартных Подсистем (БСП). Писать "велосипеды" в таком случае не нужно.
В общем модуле СтроковыеФункцииКлиентСервер уже реализована оптимизированная функция удаления символов с конца:
Наименование = Номенклатура.Наименование;
// Функция безопасно удалит 2 последних символа
Результат = СтроковыеФункцииКлиентСервер.УдалитьПоследнийСимволВСтроке(Наименование, 2);
Применение готовых функций БСП снижает количество потенциальных ошибок в коде и упрощает последующую поддержку и обновление конфигурации.
В рамках обсуждения на форуме прозвучало предложение использовать конструкцию ВЫРАЗИТЬ() в запросе (Сообщение 5) для усечения длины. Выясним, почему этот подход ошибочен:
ВЫРАЗИТЬ(Номенклатура.Наименование КАК СТРОКА(98)) не обрезает строку переменной длины на 2 символа. Если длина строки меньше 98 символов, СУБД вернет ее без изменений. Если же строка приводится к фиксированной длине, СУБД просто дополнит результат пробелами справа.СтрДлина()). Из-за этого динамически вычислить позицию обрезки на уровне СУБД стандартными средствами невозможно.Форматирование строк и изменение их структуры — это классическая задача программного кода (на клиенте или сервере приложений), а не СУБД. Оставьте запросам выборку данных, а обработку строк выполняйте с помощью рассмотренных выше методов.