При переходе со старых версий платформ, например с 1С 7.7 на 1С 8, часто возникают проблемы с кодировкой. Из-за этого в текстовых реквизитах справочников появляются некорректные символы или «кракозябры» (особенно это касается специфических символов национальных алфавитов). Чтобы не исправлять данные вручную, мы можем написать специальную обработку. Рассмотрим подробнее, как правильно перебрать элементы справочника, найти ошибки и массово произвести замену символов, избежав при этом типичных ошибок.
Проанализируем ситуацию на основе примера. Часто начинающие разработчики пытаются перебрать справочник с помощью конструкции Выбрать() и применить функцию СтрЗаменить для исправления символов. Посмотрим на код, который содержит сразу две логические ошибки:
Выборка = Справочники.Контрагенты.Выбрать();
Пока Выборка.Следующий() Цикл
Замена = Выборка.Наименование;
Стр = СтрЗаменить(Замена,"є","ғ");
Стр = СтрЗаменить(Замена,"Є","Ғ");
// ... другие замены
КонецЦикла;
Выясним причину, почему этот код не работает:
СтрЗаменить берет исходную переменную Замена и помещает результат в переменную Стр. Каждая последующая строка снова берет первоначальную Замена, игнорируя предыдущие исправления. В результате сохраняется только последняя замена.Чтобы данные сохранились, перепишем код. Изменим логику присвоения переменных: результат функции мы будем возвращать в ту же самую переменную Замена. Также добавим получение объекта по ссылке и его запись:
Выборка = Справочники.Контрагенты.Выбрать();
Пока Выборка.Следующий() Цикл
Замена = Выборка.Наименование;
Замена = СтрЗаменить(Замена,"є","ғ");
Замена = СтрЗаменить(Замена,"Є","Ғ");
// ... другие замены
Об = Выборка.ПолучитьОбъект();
Об.Наименование = Замена;
Об.ОбменДанными.Загрузка = Истина;
Об.Записать();
КонецЦикла;
Обратим внимание на конструкцию ОбменДанными.Загрузка = Истина. Для задачи исправления исторических данных это критически важный шаг. Данный флаг отключает платформенные проверки заполнения реквизитов и игнорирует проверки бизнес-логики в обработчиках «ПередЗаписью» и «ПриЗаписи». Перенесенные старые контрагенты могут не соответствовать современным жестким правилам базы (например, у них может быть не заполнен ИНН), и без этого флага 1С просто выдаст ошибку и откажется сохранять исправленное имя.
Приведенный выше код рабочий, но он крайне неэффективен, если в справочнике десятки тысяч элементов. Метод Выбрать() обходит абсолютно все записи. Кроме того, операция записи ресурсоемка, и в текущем виде метод Записать() вызывается даже для тех контрагентов, у которых наименование изначально было корректным. Рассмотрим по шагам, как кардинально ускорить обработку.
ПОДОБНО в секции ГДЕ.Если Выборка.Наименование <> Замена Тогда. Только в случае выявления разницы следует получать объект и записывать его. Это убережет базу от лишних блокировок.НачатьТранзакцию() перед циклом и ЗафиксироватьТранзакцию() после. Если элементов много, транзакции лучше фиксировать порциями, например, каждые 1000 элементов.Посмотрим на пример оптимизированного кода, который учитывает эти рекомендации:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Контрагенты.Ссылка КАК Ссылка,
| Контрагенты.Наименование КАК Наименование
|ИЗ
| Справочник.Контрагенты КАК Контрагенты
|ГДЕ
| (Контрагенты.Наименование ПОДОБНО ""%є%""
| ИЛИ Контрагенты.Наименование ПОДОБНО ""%Є%"")"; // Добавляем нужные условия
Выборка = Запрос.Выполнить().Выбрать();
НачатьТранзакцию();
Счетчик = 0;
Пока Выборка.Следующий() Цикл
Замена = Выборка.Наименование;
Замена = СтрЗаменить(Замена,"є","ғ");
Замена = СтрЗаменить(Замена,"Є","Ғ");
Если Выборка.Наименование <> Замена Тогда
Об = Выборка.Ссылка.ПолучитьОбъект();
Об.Наименование = Замена;
Об.ОбменДанными.Загрузка = Истина;
Об.Записать();
Счетчик = Счетчик + 1;
// Фиксируем транзакцию порциями
Если Счетчик % 1000 = 0 Тогда
ЗафиксироватьТранзакцию();
НачатьТранзакцию();
КонецЕсли;
КонецЕсли;
КонецЦикла;
ЗафиксироватьТранзакцию();
При кривом переносе данных страдают, как правило, все текстовые поля. Не забудьте проверить реквизит НаименованиеПолное и другие строковые поля справочника — функцию замены потребуется применить и к ним.
Кроме того, если вы работаете в современных конфигурациях на управляемых формах, этот код необходимо выполнять исключительно на стороне сервера. Для этого используем директиву &НаСервере. Выполнение циклов перебора, получение объектов и их запись на стороне клиента катастрофически замедляет работу из-за постоянных обращений к базе данных через сеть. Перенос всей логики в серверную процедуру сделает обработку данных быстрой и стабильной.