При разработке интерфейсов печати, обработки табличных частей или пакетной выгрузки часто возникает задача: пользователь вводит список строк или страниц в привычном виде, например "5-15, 18, 40", а разработчику необходимо получить результирующий массив чисел [5, 6, 7, ..., 15, 18, 40]. Разберем различные подходы к решению этой задачи на платформе 1С:Предприятие.
Проанализируем наиболее компактный и современный способ, доступный в платформе 1С 8.3 начиная с релиза 8.3.6. Алгоритм состоит из двух шагов: сначала разделяем строку по запятым на отдельные фрагменты, а затем каждый фрагмент проверяем на наличие дефиса.
Посмотрим на практическую реализацию в виде готовой функции:
Функция РазобратьСтрокуДиапазоновВМассив(Знач ВходнаяСтрока) Экспорт
Результат = Новый Массив;
// Очищаем строку от пробелов
ВходнаяСтрока = СтрЗаменить(ВходнаяСтрока, " ", "");
ВходнаяСтрока = СтрЗаменить(ВходнаяСтрока, Символы.НПП, "");
// Разбиваем строку по запятым с пропуском пустых элементов
ФрагментыЗапятых = СтрРазделить(ВходнаяСтрока, ",", Ложь);
Для Каждого ТекФрагмент Из ФрагментыЗапятых Цикл
ГраницыИнтервала = СтрРазделить(ТекФрагмент, "-", Ложь);
Если ГраницыИнтервала.Количество() = 1 Тогда
// Одиночный номер
Попытка
Результат.Добавить(Число(ГраницыИнтервала[0]));
Исключение
// Пропускаем некорректно введенные символы
КонецПопытки;
ИначеЕсли ГраницыИнтервала.Количество() = 2 Тогда
// Интервал от Мин до Макс
Попытка
НачалоИнтервала = Число(ГраницыИнтервала[0]);
КонецИнтервала = Число(ГраницыИнтервала[1]);
// Корректно обрабатываем случай, если пользователь указал обратный диапазон (например, 15-5)
Шаг = ?(НачалоИнтервала <= КонецИнтервала, 1, -1);
ТекЧисло = НачалоИнтервала;
Пока Истина Цикл
Результат.Добавить(ТекЧисло);
Если ТекЧисло = КонецИнтервала Тогда
Прервать;
КонецЕсли;
ТекЧисло = ТекЧисло + Шаг;
КонецЦикла;
Исключение
// Ошибка преобразования к числу
КонецПопытки;
КонецЕсли;
КонецЦикла;
Возврат Результат;
КонецФункции
Если код должен работать в старых версиях платформы или в конфигурациях без поддержки СтрРазделить, можно использовать классический прием платформы: замену разделителей на перевод строки Символы.ПС с последующим обходом через СтрЧислоСтрок и СтрПолучитьСтроку.
Разберем по шагам этот алгоритм:
Для Ном = 1 По СтрЧислоСтрок(...).
Функция ПолучитьНомераСтрокМногострочнымРазбором(Знач ИсходныйТекст) Экспорт
Результат = Новый Массив;
ТекстБезПробелов = СтрЗаменить(ИсходныйТекст, " ", "");
СтрокиПоЗапятым = СтрЗаменить(ТекстБезПробелов, ",", Символы.ПС);
КоличествоЗапятых = СтрЧислоСтрок(СтрокиПоЗапятым);
Для Ном = 1 По КоличествоЗапятых Цикл
ТекущаяПодстрока = СтрПолучитьСтроку(СтрокиПоЗапятым, Ном);
Если ПустаяСтрока(ТекущаяПодстрока) Тогда
Продолжить;
КонецЕсли;
СтрокиПоДефису = СтрЗаменить(ТекущаяПодстрока, "-", Символы.ПС);
КоличествоДефисов = СтрЧислоСтрок(СтрокиПоДефису);
Если КоличествоДефисов > 1 Тогда
ЛеваяГраница = Число(СтрПолучитьСтроку(СтрокиПоДефису, 1));
ПраваяГраница = Число(СтрПолучитьСтроку(СтрокиПоДефису, 2));
Для Индекс = ЛеваяГраница По ПраваяГраница Цикл
Результат.Добавить(Индекс);
КонецЦикла;
Иначе
Результат.Добавить(Число(ТекущаяПодстрока));
КонецЕсли;
КонецЦикла;
Возврат Результат;
КонецФункции
В типовых конфигурациях 1С для работы со строками рекомендуется использовать функции общего назначения из БСП. Функция СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок позволяет безопасно разбить строку на массив элементов с автоматической обрезкой незначащих пробелов.
Функция РазобратьСтрокуЧерезБСП(Знач ВходнаяСтрока) Экспорт
Результат = Новый Массив;
Подстроки = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(ВходнаяСтрока, ",", Истина, Истина);
Для Каждого Подстрока Из Подстроки Цикл
ЧастиИнтервала = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(Подстрока, "-", Истина, Истина);
Если ЧастиИнтервала.Количество() = 1 Тогда
Результат.Добавить(Число(ЧастиИнтервала[0]));
ИначеЕсли ЧастиИнтервала.Количество() = 2 Тогда
От = Число(ЧастиИнтервала[0]);
До = Число(ЧастиИнтервала[1]);
Для Номер = От По До Цикл
Результат.Добавить(Номер);
КонецЦикла;
КонецЕсли;
КонецЦикла;
Возврат Результат;
КонецФункции
Выясним частую сопутствующую проблему: если пользователь передал пересекающиеся интервалы (например, "1-5, 3-7") или нарушил порядок ввода ("10, 2, 5"), результирующий массив может содержать повторяющиеся значения и не быть упорядоченным.
Так как у стандартного объекта Массив в 1С нет метода сортировки, для упорядочивания и устранения дубликатов удобно использовать вспомогательные коллекции:
Коллекция.Вставить(ЧисловоеЗначение, Истина)).СписокЗначений и вызываем Список.СортироватьПоЗначению(НаправлениеСортировки.Возр).Число, вызываем ТЗ.Свернуть("НомерСтроки") и ТЗ.Сортировать("НомерСтроки Возр").Важное предостережение: Избегайте использования вызовов через COMОбъект("VBScript.RegExp") и функцию Выполнить(). Использование COM-объектов нарушает кроссплатформенность конфигурации (код не сможет выполниться на сервере под управлением Linux или в веб-клиенте), а вызов Выполнить() создает потенциальную уязвимость для выполнения произвольного кода и заблокирован в безопасном режиме.