В процессе разработки часто возникает задача очистки данных, полученных от пользователя или из внешних систем. Одной из классических задач является удаление лишних пробелов и повторяющихся символов. Например, если на входе мы имеем строку "abc cde def", результатом обработки должна стать строка "abcdef". Разберем несколько способов решения этой задачи в среде 1С:Предприятие, проанализируем их эффективность и выберем оптимальный вариант для разных ситуаций.
Проанализируем самый быстрый способ обработки длинных строк. Объект Соответствие (Match) идеально подходит для поиска уникальных элементов, так как поиск по ключу в нем реализован крайне эффективно. Основная идея заключается в том, чтобы обходить исходную строку посимвольно и добавлять каждый новый символ в Соответствие. Если символ уже встречался, мы его просто игнорируем.
Рассмотрим по шагам реализацию этого метода:
СтрЗаменить.Соответствие для хранения уникальных символов.Массив, в который будем складывать символы в порядке их появления (так как Соответствие не гарантирует сохранение порядка).
// Входная строка
ИсходнаяСтрока = "abc cde def";
// Шаг 1: Убираем пробелы сразу
ЧистаяСтрока = СтрЗаменить(ИсходнаяСтрока, " ", "");
УникальныеСимволы = Новый Соответствие;
РезультатМассив = Новый Массив;
// Шаг 2-4: Обход строки
Для Сч = 1 По СтрДлина(ЧистаяСтрока) Цикл
ТекущийСимвол = Сред(ЧистаяСтрока, Сч, 1);
// Проверяем, встречался ли символ ранее
Если УникальныеСимволы[ТекущийСимвол] = Неопределено Тогда
УникальныеСимволы.Вставить(ТекущийСимвол, Истина);
РезультатМассив.Добавить(ТекущийСимвол);
КонецЕсли;
КонецЦикла;
// Шаг 5: Сборка результата
Результат = СтрСоединить(РезультатМассив, "");
// Результат будет "abcdef"
Важное замечание: В отличие от объекта Структура, объект Соответствие позволяет использовать в качестве ключа любые значения, включая цифры и спецсимволы, что критически важно при работе с произвольным текстом.
Если строка небольшая и производительность не является критическим фактором, можно использовать более простой и читаемый код. Мы будем формировать результирующую строку, проверяя наличие текущего символа в уже собранном результате.
Рассмотрим пример реализации:
ИсходнаяСтрока = "abc cde def";
Результат = "";
Для А = 1 По СтрДлина(ИсходнаяСтрока) Цикл
Симв = Сред(ИсходнаяСтрока, А, 1);
// Проверяем: если это не пробел и символа еще нет в результате
Если Симв <> " " И СтрНайти(Результат, Симв) = 0 Тогда
Результат = Результат + Симв;
КонецЕсли;
КонецЦикла;
Выясним причину, по которой этот метод может работать медленнее на больших объемах данных. При каждой операции Результат = Результат + Симв система 1С создает в памяти новую строку, копируя в нее содержимое старой. На строках в десятки тысяч символов это может вызвать заметные задержки.
Существует еще один интересный алгоритм, который «вырезает» найденный символ из всей оставшейся части строки. Это позволяет сократить количество итераций цикла в некоторых случаях.
ВходящаяСтрока = "abc cde def";
// Предварительно удаляем пробелы
ВходящаяСтрока = СтрЗаменить(ВходящаяСтрока, " ", "");
Результат = "";
Пока СтрДлина(ВходящаяСтрока) > 0 Цикл
// Берем самый первый символ
ТекущийСимвол = Лев(ВходящаяСтрока, 1);
Результат = Результат + ТекущийСимвол;
// Удаляем ВСЕ вхождения этого символа из оставшейся строки
ВходящаяСтрока = СтрЗаменить(ВходящаяСтрока, ТекущийСимвол, "");
КонецЦикла;
Этот подход элегантен, но стоит помнить, что функция СтрЗаменить при каждом вызове сканирует всю строку целиком, что также накладывает свои ограничения на скорость при работе с очень длинными текстами.
Иногда программисты предпочитают использовать встроенные механизмы агрегации 1С, такие как метод Свернуть() у объекта ТаблицаЗначений. Несмотря на то, что этот метод требует вызова сервера (так как таблицы значений недоступны на тонком клиенте без контекста), он может быть удобен, если данные в дальнейшем нужно сортировать или обрабатывать как коллекцию.
Разберем этот процесс:
Свернуть по колонке с символом.
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Символ");
Для Сч = 1 По СтрДлина(Строка) Цикл
ТекСимвол = Сред(Строка, Сч, 1);
Если ТекСимвол <> " " Тогда
ТЗ.Добавить().Символ = ТекСимвол;
КонецЕсли;
КонецЦикла;
// Магия 1С: удаляем дубли одной командой
ТЗ.Свернуть("Символ");
Результат = "";
Для Каждого Стр Из ТЗ Цикл
Результат = Результат + Стр.Символ;
КонецЦикла;
Проанализируем технические тонкости, которые могут повлиять на результат работы ваших алгоритмов:
Соответствии и функция СтрНайти учитывают регистр. Это значит, что символы "А" и "а" будут считаться разными. Если вам нужно считать их дублями, перед обработкой используйте функцию ВРег() (в верхний регистр) или НРег() (в нижний).СтрНайти появилась в версии 8.3.10. Если вы работаете на более старой платформе (например, 8.2), следует использовать функцию Найти.СтрЗаменить(Стр, Символы.НПП, "").Подводя итог, можно сказать, что для большинства повседневных задач оптимальным является Способ 1 (Соответствие + Массив), так как он обеспечивает стабильную скорость и корректно обрабатывает любые символы в строке.