В процессе разработки на платформе 1С:Предприятие часто возникают задачи, связанные с нестандартной обработкой текстовой информации. Одной из таких задач является поочередное (шахматное) объединение символов из двух разных строк. Например, если у нас есть строка "Привет" и строка "Мир!!!", мы можем захотеть получить результат вида "ПМ ри в! е! т!". В этой статье мы подробно разберем, как реализовать такой алгоритм, рассмотрим различные сценарии обработки данных и оптимизируем код для обеспечения максимальной производительности.
Для начала рассмотрим самую простую ситуацию, когда нам необходимо перебрать две строки и соединить их символы попарно. Основным инструментом для решения этой задачи в языке 1С является функция Сред(). Эта функция позволяет извлечь один или несколько символов из строки, начиная с определенной позиции.
Синтаксис функции: Сред(Строка, НачальныйНомер, Количество). Чтобы получить один символ, мы всегда будем указывать 1 в качестве третьего параметра.
Давайте разберем по шагам простейший пример кода, который подходит для строк одинаковой длины:
&НаКлиенте
Процедура ОбъединитьСтроки(Команда)
Строка1 = "Привет";
Строка2 = "Мир!!!";
Результат = "";
// Определяем длину цикла по первой строке
Для НомерСимвола = 1 По СтрДлина(Строка1) Цикл
// Извлекаем текущие символы из обеих строк
Символ1 = Сред(Строка1, НомерСимвола, 1);
Символ2 = Сред(Строка2, НомерСимвола, 1);
// Соединяем их и выводим в результат
Результат = Результат + Символ1 + Символ2;
КонецЦикла;
Сообщить(Результат); // Выведет "ПМ ри в! е! т!"
КонецПроцедуры
В данном примере мы используем цикл Для...По, где счетчик НомерСимвола последовательно принимает значения от 1 до общего количества символов в строке. На каждой итерации мы берем по одному знаку из каждого источника и приклеиваем их к итоговой переменной Результат.
На практике данные редко бывают идеальными. Выясним причину, по которой предыдущий код может работать некорректно: если вторая строка длиннее первой, цикл завершится слишком рано, и "хвост" второй строки будет потерян. Если же короче — функция Сред() просто вернет пустую строку для отсутствующих позиций.
Проанализируем ситуацию, когда нам нужно гарантированно обработать все символы из обеих строк, независимо от того, какая из них длиннее. Для этого нам потребуется функция Макс(), которая поможет определить верхнюю границу цикла.
Рассмотрим улучшенный вариант решения:
&НаКлиенте
Процедура РезультатУниверсальный(Команда)
Стр1 = Объект.Строка1;
Стр2 = Объект.Строка2;
ИтоговаяСтрока = "";
// Находим максимальную длину среди двух строк
МаксДлина = Макс(СтрДлина(Стр1), СтрДлина(Стр2));
Для Позиция = 1 По МаксДлина Цикл
// Извлекаем символы. Если позиция превышает длину строки,
// функция Сред() вернет пустую строку ""
Символ1 = Сред(Стр1, Позиция, 1);
Символ2 = Сред(Стр2, Позиция, 1);
ИтоговаяСтрока = ИтоговаяСтрока + Символ1 + Символ2;
КонецЦикла;
Сообщить(ИтоговаяСтрока);
КонецПроцедуры
Важный нюанс: Платформа 1С устроена так, что функция Сред() является "безопасной". Если вы попытаетесь обратиться к 10-му символу в строке, длина которой всего 5 символов, система не выдаст ошибку "Индекс находится за границами массива", а просто вернет пустую строку. Это позволяет нам не писать дополнительные проверки Если...Тогда внутри цикла, что делает код чище и понятнее.
Если вам необходимо обрабатывать очень длинные строки (например, тексты объемом в десятки тысяч символов), обычное сложение строк через оператор + может существенно замедлить работу программы. Это происходит потому, что строки в памяти компьютера являются неизменяемыми объектами. При каждом сложении Строка = Строка + Символ система создает в памяти совершенно новую строку, копируя туда старые данные. При большом количестве итераций это создает колоссальную нагрузку на процессор и память.
Посмотрим на пример профессионального подхода с использованием массива и функции СтрСоединить():
Добавить().
&НаСервере
Функция ПолучитьОптимизированнуюСтроку(Текст1, Текст2)
МассивРезультата = Новый Массив;
Длина1 = СтрДлина(Текст1);
Длина2 = СтрДлина(Текст2);
Предел = Макс(Длина1, Длина2);
Для Индекс = 1 По Предел Цикл
Символ1 = Сред(Текст1, Индекс, 1);
Если ЗначениеЗаполнено(Символ1) Тогда
МассивРезультата.Добавить(Символ1);
КонецЕсли;
Символ2 = Сред(Текст2, Индекс, 1);
Если ЗначениеЗаполнено(Символ2) Тогда
МассивРезультата.Добавить(Символ2);
КонецЕсли;
КонецЦикла;
// Соединяем все накопленные элементы без разделителя
Возврат СтрСоединить(МассивРезультата, "");
КонецФункции
Метод СтрСоединить() работает гораздо быстрее простого сложения, так как выделение памяти происходит один раз для всего результирующего объема данных. Обратите внимание, что мы добавили проверку ЗначениеЗаполнено() — это позволит избежать появления "лишних" невидимых пустот, если строки имеют разную длину и мы не хотим, чтобы пустые места от короткой строки занимали место в результате.
Разберем ситуацию с кодировками. Платформа 8.3 использует кодировку UTF-16. Для большинства привычных нам букв и цифр один символ занимает одну позицию, и СтрДлина() вместе со Сред() работают идеально. Однако существуют редкие символы (например, сложные эмодзи или специфические восточные иероглифы), которые кодируются суррогатными парами и формально могут занимать две позиции. В обычных бизнес-задачах 1С (бухгалтерия, склад, торговля) такие символы встречаются крайне редко, но при разработке чат-ботов или интеграций с мессенджерами об этом стоит помнить.
Для стандартных текстовых полей на управляемых формах предложенные выше методы являются эталонными и рекомендуются к применению.
Мы рассмотрели три способа реализации поочередного вывода символов:
Используя эти приемы, вы сможете эффективно манипулировать строковыми данными в своих обработках и конфигурациях, обеспечивая стабильную работу приложения.