При работе с большими массивами данных в 1С, например, при обработке справочника контрагентов на 100 000 и более записей, скорость выполнения простейших функций очистки строки может стать критическим фактором. Часто стандартные алгоритмы перебора символов занимают слишком много времени (до нескольких минут), что неприемлемо для оперативной работы. В рамках данной статьи мы проанализируем ситуацию, разберем типичные ошибки производительности и рассмотрим пошагово несколько способов оптимизации кода для преобразования телефонных номеров.
Рассмотрим типичную ситуацию: у нас есть функция преобрНТ(нт), которая должна очистить номер телефона от префиксов «+7», «+8» или лидирующей восьмерки, а затем оставить в строке только цифры. Изначально код может выглядеть так:
Функция преобрНТ(ЗНАЧ нт)
Если Лев(нт, 2) = "+7" Тогда нт = сред(нт, 3);
ИначеЕсли Лев(нт, 2) = "+8" Тогда нт = сред(нт, 3);
ИначеЕсли Лев(нт, 1) = "8" Тогда нт = сред(нт, 2);
КонецЕсли;
стр = "";
Для сч = 1 по СтрДлина(нт) Цикл
см = Сред(нт, сч, 1);
Если КодСимвола(см)>=КодСимвола("0") И КодСимвола(см)<=КодСимвола("9") Тогда
стр = стр + см;
КонецЕсли;
КонецЦикла;
Возврат стр;
КонецФункции
Почему этот код работает медленно? Основные причины кроются в многократном вызове тяжелых функций внутри цикла (например, КодСимвола) и неоптимальной логике сравнения строк. Проанализируем, как можно улучшить этот алгоритм, двигаясь от простых правок к системным решениям.
Первое, на что стоит обратить внимание — это замена классической конструкции Если...Тогда на тернарный оператор ?(). Как показывает практика, встроенный интерпретатор 1С обрабатывает тернарные операторы быстрее. Также мы можем заменить последовательные проверки Лев() на функцию СтрЗаменить(), если уверены в структуре данных.
Разберем конкретные улучшения:
КодСимвола("0") и КодСимвола("9") возвращают фиксированные значения. Вычислять их на каждой итерации цикла (например, 10 раз для каждого из 100 000 номеров) — это колоссальная трата ресурсов.КодСимвола() вообще.Посмотрим на оптимизированный промежуточный вариант:
Функция преобрНТ_Ускоренная(ЗНАЧ нт)
// Используем тернарный оператор для быстрой очистки префиксов
нт = ?(Лев(нт, 2) = "+7" ИЛИ Лев(нт, 2) = "+8", Сред(нт, 3), нт);
нт = ?(Лев(нт, 1) = "8", Сред(нт, 2), нт);
Результат = "";
Для сч = 1 по СтрДлина(нт) Цикл
см = Сред(нт, сч, 1);
// Прямое сравнение строк быстрее вызова КодСимвола
Если см >= "0" И см <= "9" Тогда
Результат = Результат + см;
КонецЕсли;
КонецЦикла;
Возврат Результат;
КонецФункции
Если ваша конфигурация работает на современной платформе (начиная с 8.3.10), можно применить элегантный и крайне быстрый способ очистки строки от любых нецифровых символов без использования циклов Для. Метод заключается в разделении строки по массиву «мусорных» символов и последующем соединении частей обратно.
Выясним, как это работает на практике:
Функция ОчиститьНомерБыстро(СтрокаСЦифрами)
// Оставляем только то, что входит в набор 0123456789
// Сначала находим все символы, которые НЕ являются цифрами
Разделители = СтрСоединить(СтрРазделить(СтрокаСЦифрами, "0123456789", Ложь));
// Теперь разделяем исходную строку по этим мусорным символам и соединяем
Возврат СтрСоединить(СтрРазделить(СтрокаСЦифрами, Разделители, Ложь));
КонецФункции
Этот метод работает на уровне движка платформы (написанного на C++), что дает прирост скорости в несколько раз по сравнению с любым циклом внутри кода 1С.
Для сложных задач очистки, где могут встречаться невидимые символы, точки, дефисы или скобки в произвольных местах, идеально подходят регулярные выражения. Рассмотрим, как реализовать это правильно. Важный момент: создание объекта VBScript.RegExp — операция дорогая, поэтому объект нужно создавать один раз вне цикла обработки.
Проанализируем пример кода:
// Пример вызова для массива данных
RegExp = Новый COMОбъект("VBScript.RegExp");
RegExp.Global = Истина;
RegExp.IgnoreCase = Истина;
RegExp.Pattern = "[^\d]"; // Шаблон: найти всё, что НЕ является цифрой
Для Каждого СтрокаДанных Из МассивНомеров Цикл
ЧистыйНомер = RegExp.Replace(СтрокаДанных.Номер, "");
// Дальнейшая обработка...
КонецЦикла;
Использование регулярных выражений позволяет одним махом убрать все лишние знаки, включая пробелы и тире, обеспечивая высокую надежность кода.
Помимо оптимизации самого кода, стоит рассмотреть системные улучшения, которые помогут избежать проблемы медленной обработки в будущем:
ПередЗаписью). В базе данных номер должен храниться в виде строки, состоящей только из цифр. Для отображения пользователю можно использовать маску.НомерДляПоиска, где будут храниться только цифры.СтроковыеФункцииКлиентСервер.ТолькоЦифрыВСтроке(). Разработчики фирмы «1С» уже оптимизировали её под текущую версию платформы.Подведем итог: даже простая замена КодСимвола на прямое сравнение и вынос условий за пределы цикла могут ускорить обработку на 20-30%. Переход же на современные методы платформы или регулярные выражения сокращает время выполнения задачи с минут до секунд.