Как программно изменить часть наименования номенклатуры в 1С:Предприятии?

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

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

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

Базовый алгоритм решения задачи

Для того чтобы точечно заменить слова в наименовании (например, превратить «Арбуз сушеный красный 54кг» в «Сушеный арбуз красный 54кг», изменив только первые два слова и не затронув остальную часть), нам необходимо выполнить три основных шага:

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

Рассмотрим пошагово реализацию этого алгоритма на конкретных примерах.

Шаг 1. Написание безопасного и быстрого запроса

Первая частая ошибка начинающих разработчиков — выборка всех элементов справочника без предварительного фильтра. Если в вашей базе данных более 100 000 товаров, простая выборка всех элементов приведет к зависанию системы. Поэтому мы обязательно используем конструкцию ПОДОБНО в секции ГДЕ нашего запроса.

Вторая критическая ошибка — попытка изменить реквизиты групп (папок) справочника номенклатуры. Группы в 1С часто имеют ограничения по составу реквизитов, и попытка обращения к реквизиту вроде НаименованиеПолное у группы вызовет ошибку «Реквизит недоступен для группы», что полностью прервет выполнение обработки. Чтобы избежать этого, в запросе обязательно нужно отфильтровать группы с помощью условия И НЕ Номенклатура.ЭтоГруппа.

Давайте проанализируем правильный вариант построения запроса с использованием параметров:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Номенклатура.Ссылка КАК Ссылка
    |ИЗ
    |	Справочник.Номенклатура КАК Номенклатура
    |ГДЕ
    |	Номенклатура.Наименование ПОДОБНО &ИскомыйТекст
    |	И НЕ Номенклатура.ЭтоГруппа";

// Формируем шаблон поиска для оператора ПОДОБНО. Проценты (%) означают любое количество любых символов.
Запрос.УстановитьПараметр("ИскомыйТекст", "%" + Объект.ЧтоИщем + "%");
Выборка = Запрос.Выполнить().Выбрать();

Шаг 2. Обход выборки и программная замена наименования

После того как мы получили точечную выборку элементов, мы переходим к их изменению. Для замены подстроки используется встроенная функция СтрЗаменить(). Нам необходимо получить объект по ссылке, перезаписать его наименование и вызвать метод записи в блоке Попытка...Исключение, чтобы обработка не прерывалась из-за единичной ошибки (например, если элемент заблокирован другим пользователем).

Выясним, как выглядит полный цикл обработки данных:


Пока Выборка.Следующий() Цикл
    
    // Получаем объект для редактирования
    НоменклатураОбъект = Выборка.Ссылка.ПолучитьОбъект();
    
    // Выполняем замену текста в наименовании
    СтароеНаименование = НоменклатураОбъект.Наименование;
    НовоеНаименование = СтрЗаменить(СтароеНаименование, Объект.ЧтоИщем, Объект.НаЧтоЗаменяем);
    
    // Присваиваем новое значение реквизитам наименования
    НоменклатураОбъект.Наименование = НовоеНаименование;
    
    // Часто в конфигурациях используется реквизит НаименованиеПолное, обновим и его
    Если ОбщегоНазначения.ЕстьРеквизитОбъекта("НаименованиеПолное", НоменклатураОбъект) Тогда
        НоменклатураОбъект.НаименованиеПолное = НовоеНаименование;
    КонецЕсли;
    
    // Безопасная запись объекта
    Попытка
        НоменклатураОбъект.Записать();
        Сообщить("Успешно изменено: " + СтароеНаименование + " -> " + НовоеНаименование);
    Исключение
        Сообщить("Не удалось записать элемент: " + Выборка.Ссылка + ". Ошибка: " + ОписаниеОшибки());
    КонецПопытки;
    
КонецЦикла;

Продвинутый уровень: Оптимизация для больших баз и крупных справочников

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

1. Отключение бизнес-логики и проверок перед записью. При стандартной записи объекта 1С запускает все подписки на события, проверки заполнения реквизитов, регламенты контроля уникальности штрихкодов и прочее. Это отнимает колоссальное количество времени и может вызывать ошибки, если старые карточки товаров были заполнены некорректно. Мы можем временно отключить эти проверки с помощью флага ОбменДанными.Загрузка:


НоменклатураОбъект.ОбменДанными.Загрузка = Истина;
НоменклатураОбъект.Записать();

2. Использование транзакций. Запись каждого объекта по отдельности держит базу данных в постоянном напряжении, совершая множество мелких дисковых операций записи. Объединение изменений в пакетные транзакции (например, по 500 элементов) ускоряет работу алгоритма в десятки раз. Разберем, как реализовать пакетную запись с использованием транзакций:


КоличествоВТранзакции = 500;
Счетчик = 0;

НачатьТранзакцию();

Пока Выборка.Следующий() Цикл
    
    НоменклатураОбъект = Выборка.Ссылка.ПолучитьОбъект();
    НоменклатураОбъект.Наименование = СтрЗаменить(НоменклатураОбъект.Наименование, Объект.ЧтоИщем, Объект.НаЧтоЗаменяем);
    
    НоменклатураОбъект.ОбменДанными.Загрузка = Истина;
    
    Попытка
        НоменклатураОбъект.Записать();
        Счетчик = Счетчик + 1;
    Исключение
        ОтменитьТранзакцию();
        Сообщить("Критическая ошибка при записи пакета. Транзакция отменена. Ошибка: " + ОписаниеОшибки());
        Возврат;
    КонецПопытки;
    
    // Если набрался пакет, фиксируем текущую транзакцию и открываем новую
    Если Счетчик % КоличествоВТранзакции = 0 Тогда
        ЗафиксироватьТранзакцию();
        НачатьТранзакцию();
    КонецЕсли;
    
КонецЦикла;

// Закрываем последнюю открытую транзакцию, если в ней остались элементы
Если ТранзакцияАктивна() Тогда
    ЗафиксироватьТранзакцию();
КонецЕсли;

Современный подход: Регулярные выражения в 1С (Платформа 8.3.23 и выше)

Что делать, если искомая подстрока написана с ошибками, лишними пробелами или в разном регистре символов (например: «арбуз сушеный», «Арбуз сушеный», «Арбуз, сушеный»)? Раньше для этого приходилось подключать медленные внешние компоненты. Начиная с версии платформы 8.3.23, разработчикам доступен нативный механизм работы с регулярными выражениями.

Давайте посмотрим на пример использования новой функции СтрЗаменитьПоРегулярномуВыражению(). Данный метод позволяет выполнить гибкую замену текста без учета лишних пробелов и регистра букв:


// Шаблон регулярного выражения ищет слово "арбуз" и слово "сушеный" 
// независимо от регистра букв и количества пробелов между ними.
ШаблонПоиска = "(?i)арбуз\s+сушеный"; 
НовоеЗначение = "Сушеный арбуз";

Пока Выборка.Следующий() Цикл
    НоменклатураОбъект = Выборка.Ссылка.ПолучитьОбъект();
    
    СтароеНаименование = НоменклатураОбъект.Наименование;
    
    // Замена по регулярному выражению
    НовоеНаименование = СтрЗаменитьПоРегулярномуВыражению(СтароеНаименование, ШаблонПоиска, НовоеЗначение);
    
    Если СтароеНаименование <> НовоеНаименование Тогда
        НоменклатураОбъект.Наименование = НовоеНаименование;
        НоменклатураОбъект.ОбменДанными.Загрузка = Истина;
        НоменклатураОбъект.Записать();
    КонецЕсли;
КонецЦикла;

Альтернатива программированию: Групповое изменение реквизитов

Если вам нужно выполнить замену разово и вы не хотите писать код или создавать внешнюю обработку, воспользуйтесь стандартным инструментом 1С — обработкой «Групповое изменение реквизитов» (встроена во все конфигурации на базе Библиотеки Стандартных Подсистем — БСП). Рассмотрим подробнее порядок действий:

  1. Перейдите в раздел Администрирование -> Обслуживание -> Корректировка данных -> Групповое изменение реквизитов.
  2. В поле «Выбирать элементы» укажите справочник Номенклатура.
  3. Нажмите гиперссылку «Все элементы» рядом для настройки отбора. Добавьте условие: Наименование ПОДОБНО %Арбуз сушеный% и обязательно добавьте условие Это группа Равно Нет.
  4. В списке доступных для изменения реквизитов найдите Наименование.
  5. В колонке «Новое значение» нажмите кнопку выбора и откройте конструктор формул (если он доступен в вашей версии БСП). В формуле укажите выражение замены: СтрЗаменить(Объект.Наименование, "Арбуз сушеный", "Сушеный арбуз").
  6. В дополнительных параметрах обработки (по кнопке «Дополнительные параметры») обязательно включите флаг «Выполнять в режиме загрузки данных (ОбменДанными.Загрузка = Истина)». Это гарантирует обход жестких системных проверок.
  7. Нажмите кнопку «Изменить реквизиты».

Важное предупреждение: Перед выполнением любых массовых программных изменений данных, особенно связанных со справочником «Номенклатура», обязательно делайте резервную копию информационной базы (файл .1CD или средствами СУБД MS SQL / PostgreSQL), либо выполняйте и тестируйте алгоритм на актуальной копии базы данных!

← На главную