Как ускорить код обработки и очистки телефонных номеров в 1С?

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

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

Анализ исходной проблемы и базовой логики

Рассмотрим типичную ситуацию: у нас есть функция преобрНТ(нт), которая должна очистить номер телефона от префиксов «+7», «+8» или лидирующей восьмерки, а затем оставить в строке только цифры. Изначально код может выглядеть так:


Функция преобрНТ(ЗНАЧ нт) 
    Если Лев(нт, 2) = "+7" Тогда нт = сред(нт, 3); 
    ИначеЕсли Лев(нт, 2) = "+8" Тогда нт = сред(нт, 3); 
    ИначеЕсли Лев(нт, 1) = "8" Тогда нт = сред(нт, 2); 
    КонецЕсли; 
    стр = ""; 
    Для сч = 1 по СтрДлина(нт) Цикл 
        см = Сред(нт, сч, 1); 
        Если КодСимвола(см)>=КодСимвола("0") И КодСимвола(см)<=КодСимвола("9") Тогда
            стр = стр + см;
        КонецЕсли;
    КонецЦикла; 
    Возврат стр;
КонецФункции

Почему этот код работает медленно? Основные причины кроются в многократном вызове тяжелых функций внутри цикла (например, КодСимвола) и неоптимальной логике сравнения строк. Проанализируем, как можно улучшить этот алгоритм, двигаясь от простых правок к системным решениям.

Решение 1: Микро-оптимизация условий и функций

Первое, на что стоит обратить внимание — это замена классической конструкции Если...Тогда на тернарный оператор ?(). Как показывает практика, встроенный интерпретатор 1С обрабатывает тернарные операторы быстрее. Также мы можем заменить последовательные проверки Лев() на функцию СтрЗаменить(), если уверены в структуре данных.

Разберем конкретные улучшения:

  1. Вынос констант из цикла: Функции КодСимвола("0") и КодСимвола("9") возвращают фиксированные значения. Вычислять их на каждой итерации цикла (например, 10 раз для каждого из 100 000 номеров) — это колоссальная трата ресурсов.
  2. Прямое сравнение символов: В 1С 8-й версии строковые переменные можно сравнивать напрямую (по кодам Unicode), что избавляет от необходимости вызывать КодСимвола() вообще.

Посмотрим на оптимизированный промежуточный вариант:


Функция преобрНТ_Ускоренная(ЗНАЧ нт)
    // Используем тернарный оператор для быстрой очистки префиксов
    нт = ?(Лев(нт, 2) = "+7" ИЛИ Лев(нт, 2) = "+8", Сред(нт, 3), нт);
    нт = ?(Лев(нт, 1) = "8", Сред(нт, 2), нт);
    
    Результат = "";
    Для сч = 1 по СтрДлина(нт) Цикл 
        см = Сред(нт, сч, 1); 
        // Прямое сравнение строк быстрее вызова КодСимвола
        Если см >= "0" И см <= "9" Тогда
            Результат = Результат + см;
        КонецЕсли;
    КонецЦикла; 
    Возврат Результат;
КонецФункции

Решение 2: Использование «СтрРазделить» и «СтрСоединить» (для платформы 8.3.10+)

Если ваша конфигурация работает на современной платформе (начиная с 8.3.10), можно применить элегантный и крайне быстрый способ очистки строки от любых нецифровых символов без использования циклов Для. Метод заключается в разделении строки по массиву «мусорных» символов и последующем соединении частей обратно.

Выясним, как это работает на практике:


Функция ОчиститьНомерБыстро(СтрокаСЦифрами)
    // Оставляем только то, что входит в набор 0123456789
    // Сначала находим все символы, которые НЕ являются цифрами
    Разделители = СтрСоединить(СтрРазделить(СтрокаСЦифрами, "0123456789", Ложь));
    // Теперь разделяем исходную строку по этим мусорным символам и соединяем
    Возврат СтрСоединить(СтрРазделить(СтрокаСЦифрами, Разделители, Ложь));
КонецФункции

Этот метод работает на уровне движка платформы (написанного на C++), что дает прирост скорости в несколько раз по сравнению с любым циклом внутри кода 1С.

Решение 3: Регулярные выражения (COM-объект VBScript.RegExp)

Для сложных задач очистки, где могут встречаться невидимые символы, точки, дефисы или скобки в произвольных местах, идеально подходят регулярные выражения. Рассмотрим, как реализовать это правильно. Важный момент: создание объекта VBScript.RegExp — операция дорогая, поэтому объект нужно создавать один раз вне цикла обработки.

Проанализируем пример кода:


// Пример вызова для массива данных
RegExp = Новый COMОбъект("VBScript.RegExp");
RegExp.Global = Истина;
RegExp.IgnoreCase = Истина;
RegExp.Pattern = "[^\d]"; // Шаблон: найти всё, что НЕ является цифрой

Для Каждого СтрокаДанных Из МассивНомеров Цикл
    ЧистыйНомер = RegExp.Replace(СтрокаДанных.Номер, "");
    // Дальнейшая обработка...
КонецЦикла;

Использование регулярных выражений позволяет одним махом убрать все лишние знаки, включая пробелы и тире, обеспечивая высокую надежность кода.

Рекомендации по архитектуре хранения данных

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

  1. Нормализация при записи: Самое эффективное решение — очищать номер телефона один раз в момент ввода пользователем (в событии ПередЗаписью). В базе данных номер должен храниться в виде строки, состоящей только из цифр. Для отображения пользователю можно использовать маску.
  2. Индексация: Поиск по «грязным» номерам никогда не будет быстрым. Если вам нужно искать контрагента по номеру телефона, создайте дополнительный индексированный реквизит НомерДляПоиска, где будут храниться только цифры.
  3. Использование БСП: Если в вашей базе подключена Библиотека стандартных подсистем, рассмотрите функцию СтроковыеФункцииКлиентСервер.ТолькоЦифрыВСтроке(). Разработчики фирмы «1С» уже оптимизировали её под текущую версию платформы.

Подведем итог: даже простая замена КодСимвола на прямое сравнение и вынос условий за пределы цикла могут ускорить обработку на 20-30%. Переход же на современные методы платформы или регулярные выражения сокращает время выполнения задачи с минут до секунд.

← На главную