В процессе разработки часто возникает задача обработки строковых или числовых данных, когда необходимо извлечь из них цифровые значения и произвести их суммирование. Например, это может потребоваться при анализе артикулов, парсинге входящих данных от сторонних систем или в учебных целях для отработки навыков алгоритмизации. В данной статье мы подробно разберем несколько способов реализации этой задачи, начиная от простого перебора символов и заканчивая высокопроизводительными методами платформы 1С.
Рассмотрим ситуацию, когда у нас есть массив, содержащий разнородные данные (числа и строки). Самый очевидный способ найти сумму всех входящих в них цифр — это объединить всё в одну большую строку и проанализировать каждый её символ. Разберем этот алгоритм по шагам.
Сначала мы подготовим данные, превратив их в единую текстовую последовательность. Для этого удобно использовать функцию СтрСоединить. После этого мы запустим цикл, который будет «отщипывать» по одному знаку и пытаться преобразовать его в число.
// Допустим, у нас есть исходный массив Данные
СтрокаВсехЗначений = СтрСоединить(Данные, "");
РезультатСумма = 0;
Для Инд = 1 По СтрДлина(СтрокаВсехЗначений) Цикл
ТекущийСимвол = Сред(СтрокаВсехЗначений, Инд, 1);
// Пытаемся преобразовать символ в число
Попытка
РезультатСумма = РезультатСумма + Число(ТекущийСимвол);
Исключение
// Если это была буква или спецсимвол, просто идем дальше
КонецПопытки;
КонецЦикла;
Сообщить("Итоговая сумма цифр: " + РезультатСумма);
Важный нюанс: Использование конструкции Попытка...Исключение внутри цикла — не самый производительный вариант, так как обработка исключений в 1С требует значительных системных ресурсов. Проанализируем, как можно улучшить этот код.
Выясним причину, по которой предыдущий код может работать медленно, и оптимизируем его. Вместо того чтобы вызывать исключение на каждом нечисловом символе, мы добавим явную логическую проверку. Это позволит нам корректно обрабатывать строки с любыми символами (пробелами, буквами, знаками препинания).
Посмотрим на пример реализации с условием:
СуммаЦифр = 0;
СтрокаДляАнализа = СтрСоединить(МассивДанных, "");
Для Сч = 1 По СтрДлина(СтрокаДляАнализа) Цикл
Символ = Сред(СтрокаДляАнализа, Сч, 1);
// Проверяем, входит ли символ в диапазон цифр от "0" до "9"
Если Символ >= "0" И Символ <= "9" Тогда
СуммаЦифр = СуммаЦифр + Число(Символ);
КонецЕсли;
КонецЦикла;
Сообщить(СуммаЦифр);
Этот способ гораздо «чище» и надежнее. Однако, если ваш массив данных содержит миллионы записей, даже такой цикл может занять продолжительное время. В таких случаях стоит рассмотреть более технологичные функции платформы.
Теперь рассмотрим самое элегантное и быстрое решение. Вместо того чтобы перебирать каждый символ строки (которых может быть очень много), мы можем перебрать только сами цифры от 1 до 9. Платформа 1С предоставляет встроенную функцию СтрЧислоВхождений, которая реализована на низком уровне и работает крайне быстро.
Логика такова: мы выясняем, сколько раз единица встречается в строке, и умножаем это количество на 1. Затем выясняем, сколько раз встречается двойка, и умножаем на 2, и так далее. Суммируем эти произведения. Цифра 0 на итоговую сумму не влияет, поэтому её можно пропустить.
Массив = Новый Массив;
Массив.Добавить("Артикул-35мм");
Массив.Добавить(1178.5);
СтрокаДляОбработки = СтрСоединить(Массив, "");
ИтоговаяСумма = 0;
// Цикл всего из 9 итераций вместо тысяч
Для Цифра = 1 По 9 Цикл
КоличествоВхождений = СтрЧислоВхождений(СтрокаДляОбработки, Строка(Цифра));
ИтоговаяСумма = ИтоговаяСумма + (Цифра * КоличествоВхождений);
КонецЦикла;
Сообщить("Оптимизированный расчет: " + ИтоговаяСумма);
Почему это эффективно? Представьте строку длиной в 100 000 символов. В методе №2 платформа выполнит 100 000 итераций цикла. В методе №3 — всего 9. Разница в производительности будет колоссальной.
Если мы хотим добиться еще большей производительности, разберем метод сравнения кодов символов. Сравнение строк в 1С (Символ = "1") всегда медленнее, чем сравнение целых чисел. Каждый символ имеет свой уникальный код. Цифры от 0 до 9 в кодировке Unicode имеют коды с 48 по 57 соответственно.
Проанализируем пример кода:
Сумма = 0;
Для Сч = 1 По СтрДлина(СтрокаДанных) Цикл
Код = КодСимвола(СтрокаДанных, Сч);
// Код 48 соответствует "0", код 57 соответствует "9"
Если Код >= 48 И Код <= 57 Тогда
// Чтобы получить числовое значение цифры, вычитаем код нуля
Сумма = Сумма + (Код - 48);
КонецЕсли;
КонецЦикла;
Этот подход минимизирует количество преобразований типов (строка в число), что критически важно для высоконагруженных участков кода.
При работе с реальными данными из базы 1С важно учитывать несколько специфических моментов, которые могут привести к неверным результатам:
Строка(), 1С часто добавляет неразрывный пробел (код 160) в качестве разделителя групп разрядов (например, "1 000"). Обычный СтрЗаменить(Строка, " ", "") его не удалит. Рекомендуется использовать СтрЗаменить(Строка, Символы.НПП, "").VBScript.RegExp. С его помощью можно одной командой заменить все нецифровые символы на пустую строку, после чего просуммировать остаток.Подводя итог, можно сказать, что для большинства повседневных задач оптимальным по соотношению «простота кода / скорость выполнения» является Метод №3 (использование СтрЧислоВхождений). Он наиболее устойчив к ошибкам и работает быстрее классических циклов.