В процессе ведения учета в любой информационной базе 1С со временем накапливаются ошибки в наименованиях номенклатуры. Это могут быть опечатки, лишние пробелы, неверный порядок слов или устаревшие характеристики. Вручную исправлять сотни или тысячи карточек товаров нерационально. В таких случаях перед разработчиком встает задача: быстро, безопасно и желательно без остановки работы пользователей изменить определенный набор слов в наименованиях товаров.
В этой статье мы подробно и по шагам разберем, как реализовать программную замену слов в наименовании номенклатуры. Мы рассмотрим базовые подходы на встроенном языке 1С, проанализируем типичные ошибки новичков (такие как попытка изменения групп справочника), а также разберем продвинутые методы оптимизации кода для больших баз данных, включая использование регулярных выражений и работу в обход бизнес-логики.
Для того чтобы точечно заменить слова в наименовании (например, превратить «Арбуз сушеный красный 54кг» в «Сушеный арбуз красный 54кг», изменив только первые два слова и не затронув остальную часть), нам необходимо выполнить три основных шага:
СтрЗаменить() для коррекции текста.Записать() для сохранения обновленной информации в базе данных.Рассмотрим пошагово реализацию этого алгоритма на конкретных примерах.
Первая частая ошибка начинающих разработчиков — выборка всех элементов справочника без предварительного фильтра. Если в вашей базе данных более 100 000 товаров, простая выборка всех элементов приведет к зависанию системы. Поэтому мы обязательно используем конструкцию ПОДОБНО в секции ГДЕ нашего запроса.
Вторая критическая ошибка — попытка изменить реквизиты групп (папок) справочника номенклатуры. Группы в 1С часто имеют ограничения по составу реквизитов, и попытка обращения к реквизиту вроде НаименованиеПолное у группы вызовет ошибку «Реквизит недоступен для группы», что полностью прервет выполнение обработки. Чтобы избежать этого, в запросе обязательно нужно отфильтровать группы с помощью условия И НЕ Номенклатура.ЭтоГруппа.
Давайте проанализируем правильный вариант построения запроса с использованием параметров:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Ссылка
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Наименование ПОДОБНО &ИскомыйТекст
| И НЕ Номенклатура.ЭтоГруппа";
// Формируем шаблон поиска для оператора ПОДОБНО. Проценты (%) означают любое количество любых символов.
Запрос.УстановитьПараметр("ИскомыйТекст", "%" + Объект.ЧтоИщем + "%");
Выборка = Запрос.Выполнить().Выбрать();
После того как мы получили точечную выборку элементов, мы переходим к их изменению. Для замены подстроки используется встроенная функция СтрЗаменить(). Нам необходимо получить объект по ссылке, перезаписать его наименование и вызвать метод записи в блоке Попытка...Исключение, чтобы обработка не прерывалась из-за единичной ошибки (например, если элемент заблокирован другим пользователем).
Выясним, как выглядит полный цикл обработки данных:
Пока Выборка.Следующий() Цикл
// Получаем объект для редактирования
НоменклатураОбъект = Выборка.Ссылка.ПолучитьОбъект();
// Выполняем замену текста в наименовании
СтароеНаименование = НоменклатураОбъект.Наименование;
НовоеНаименование = СтрЗаменить(СтароеНаименование, Объект.ЧтоИщем, Объект.НаЧтоЗаменяем);
// Присваиваем новое значение реквизитам наименования
НоменклатураОбъект.Наименование = НовоеНаименование;
// Часто в конфигурациях используется реквизит НаименованиеПолное, обновим и его
Если ОбщегоНазначения.ЕстьРеквизитОбъекта("НаименованиеПолное", НоменклатураОбъект) Тогда
НоменклатураОбъект.НаименованиеПолное = НовоеНаименование;
КонецЕсли;
// Безопасная запись объекта
Попытка
НоменклатураОбъект.Записать();
Сообщить("Успешно изменено: " + СтароеНаименование + " -> " + НовоеНаименование);
Исключение
Сообщить("Не удалось записать элемент: " + Выборка.Ссылка + ". Ошибка: " + ОписаниеОшибки());
КонецПопытки;
КонецЦикла;
Если перед вами стоит задача обновить наименования в крупной розничной или оптовой сети, где количество элементов номенклатуры исчисляется сотнями тысяч, простой цикл может сильно заблокировать работу базы данных. Выясним основные приемы оптимизации процесса.
1. Отключение бизнес-логики и проверок перед записью. При стандартной записи объекта 1С запускает все подписки на события, проверки заполнения реквизитов, регламенты контроля уникальности штрихкодов и прочее. Это отнимает колоссальное количество времени и может вызывать ошибки, если старые карточки товаров были заполнены некорректно. Мы можем временно отключить эти проверки с помощью флага ОбменДанными.Загрузка:
НоменклатураОбъект.ОбменДанными.Загрузка = Истина;
НоменклатураОбъект.Записать();
2. Использование транзакций. Запись каждого объекта по отдельности держит базу данных в постоянном напряжении, совершая множество мелких дисковых операций записи. Объединение изменений в пакетные транзакции (например, по 500 элементов) ускоряет работу алгоритма в десятки раз. Разберем, как реализовать пакетную запись с использованием транзакций:
КоличествоВТранзакции = 500;
Счетчик = 0;
НачатьТранзакцию();
Пока Выборка.Следующий() Цикл
НоменклатураОбъект = Выборка.Ссылка.ПолучитьОбъект();
НоменклатураОбъект.Наименование = СтрЗаменить(НоменклатураОбъект.Наименование, Объект.ЧтоИщем, Объект.НаЧтоЗаменяем);
НоменклатураОбъект.ОбменДанными.Загрузка = Истина;
Попытка
НоменклатураОбъект.Записать();
Счетчик = Счетчик + 1;
Исключение
ОтменитьТранзакцию();
Сообщить("Критическая ошибка при записи пакета. Транзакция отменена. Ошибка: " + ОписаниеОшибки());
Возврат;
КонецПопытки;
// Если набрался пакет, фиксируем текущую транзакцию и открываем новую
Если Счетчик % КоличествоВТранзакции = 0 Тогда
ЗафиксироватьТранзакцию();
НачатьТранзакцию();
КонецЕсли;
КонецЦикла;
// Закрываем последнюю открытую транзакцию, если в ней остались элементы
Если ТранзакцияАктивна() Тогда
ЗафиксироватьТранзакцию();
КонецЕсли;
Что делать, если искомая подстрока написана с ошибками, лишними пробелами или в разном регистре символов (например: «арбуз сушеный», «Арбуз сушеный», «Арбуз, сушеный»)? Раньше для этого приходилось подключать медленные внешние компоненты. Начиная с версии платформы 8.3.23, разработчикам доступен нативный механизм работы с регулярными выражениями.
Давайте посмотрим на пример использования новой функции СтрЗаменитьПоРегулярномуВыражению(). Данный метод позволяет выполнить гибкую замену текста без учета лишних пробелов и регистра букв:
// Шаблон регулярного выражения ищет слово "арбуз" и слово "сушеный"
// независимо от регистра букв и количества пробелов между ними.
ШаблонПоиска = "(?i)арбуз\s+сушеный";
НовоеЗначение = "Сушеный арбуз";
Пока Выборка.Следующий() Цикл
НоменклатураОбъект = Выборка.Ссылка.ПолучитьОбъект();
СтароеНаименование = НоменклатураОбъект.Наименование;
// Замена по регулярному выражению
НовоеНаименование = СтрЗаменитьПоРегулярномуВыражению(СтароеНаименование, ШаблонПоиска, НовоеЗначение);
Если СтароеНаименование <> НовоеНаименование Тогда
НоменклатураОбъект.Наименование = НовоеНаименование;
НоменклатураОбъект.ОбменДанными.Загрузка = Истина;
НоменклатураОбъект.Записать();
КонецЕсли;
КонецЦикла;
Если вам нужно выполнить замену разово и вы не хотите писать код или создавать внешнюю обработку, воспользуйтесь стандартным инструментом 1С — обработкой «Групповое изменение реквизитов» (встроена во все конфигурации на базе Библиотеки Стандартных Подсистем — БСП). Рассмотрим подробнее порядок действий:
Наименование ПОДОБНО %Арбуз сушеный% и обязательно добавьте условие Это группа Равно Нет.СтрЗаменить(Объект.Наименование, "Арбуз сушеный", "Сушеный арбуз").Важное предупреждение: Перед выполнением любых массовых программных изменений данных, особенно связанных со справочником «Номенклатура», обязательно делайте резервную копию информационной базы (файл .1CD или средствами СУБД MS SQL / PostgreSQL), либо выполняйте и тестируйте алгоритм на актуальной копии базы данных!