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

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

При разработке интерфейсов печати, обработки табличных частей или пакетной выгрузки часто возникает задача: пользователь вводит список строк или страниц в привычном виде, например "5-15, 18, 40", а разработчику необходимо получить результирующий массив чисел [5, 6, 7, ..., 15, 18, 40]. Разберем различные подходы к решению этой задачи на платформе 1С:Предприятие.

Вариант 1. Использование встроенной функции СтрРазделить (Рекомендуемый)

Проанализируем наиболее компактный и современный способ, доступный в платформе 1С 8.3 начиная с релиза 8.3.6. Алгоритм состоит из двух шагов: сначала разделяем строку по запятым на отдельные фрагменты, а затем каждый фрагмент проверяем на наличие дефиса.

Посмотрим на практическую реализацию в виде готовой функции:


Функция РазобратьСтрокуДиапазоновВМассив(Знач ВходнаяСтрока) Экспорт
    Результат = Новый Массив;
    
    // Очищаем строку от пробелов
    ВходнаяСтрока = СтрЗаменить(ВходнаяСтрока, " ", "");
    ВходнаяСтрока = СтрЗаменить(ВходнаяСтрока, Символы.НПП, "");
    
    // Разбиваем строку по запятым с пропуском пустых элементов
    ФрагментыЗапятых = СтрРазделить(ВходнаяСтрока, ",", Ложь);
    
    Для Каждого ТекФрагмент Из ФрагментыЗапятых Цикл
        ГраницыИнтервала = СтрРазделить(ТекФрагмент, "-", Ложь);
        
        Если ГраницыИнтервала.Количество() = 1 Тогда
            // Одиночный номер
            Попытка
                Результат.Добавить(Число(ГраницыИнтервала[0]));
            Исключение
                // Пропускаем некорректно введенные символы
            КонецПопытки;
        ИначеЕсли ГраницыИнтервала.Количество() = 2 Тогда
            // Интервал от Мин до Макс
            Попытка
                НачалоИнтервала = Число(ГраницыИнтервала[0]);
                КонецИнтервала  = Число(ГраницыИнтервала[1]);
                
                // Корректно обрабатываем случай, если пользователь указал обратный диапазон (например, 15-5)
                Шаг = ?(НачалоИнтервала <= КонецИнтервала, 1, -1);
                
                ТекЧисло = НачалоИнтервала;
                Пока Истина Цикл
                    Результат.Добавить(ТекЧисло);
                    Если ТекЧисло = КонецИнтервала Тогда
                        Прервать;
                    КонецЕсли;
                    ТекЧисло = ТекЧисло + Шаг;
                КонецЦикла;
            Исключение
                // Ошибка преобразования к числу
            КонецПопытки;
        КонецЕсли;
    КонецЦикла;
    
    Возврат Результат;
КонецФункции

Вариант 2. Разбор через СтрЗаменить и многострочный текст (Универсальный для старых версий)

Если код должен работать в старых версиях платформы или в конфигурациях без поддержки СтрРазделить, можно использовать классический прием платформы: замену разделителей на перевод строки Символы.ПС с последующим обходом через СтрЧислоСтрок и СтрПолучитьСтроку.

Разберем по шагам этот алгоритм:

  1. Заменяем запятые на перевод строк и получаем многострочный текст.
  2. Обходим строки в цикле Для Ном = 1 По СтрЧислоСтрок(...).
  3. Внутри каждой строки заменяем знак дефиса на перевод строк и проверяем количество полученных элементов.

Функция ПолучитьНомераСтрокМногострочнымРазбором(Знач ИсходныйТекст) Экспорт
    Результат = Новый Массив;
    
    ТекстБезПробелов = СтрЗаменить(ИсходныйТекст, " ", "");
    СтрокиПоЗапятым = СтрЗаменить(ТекстБезПробелов, ",", Символы.ПС);
    КоличествоЗапятых = СтрЧислоСтрок(СтрокиПоЗапятым);
    
    Для Ном = 1 По КоличествоЗапятых Цикл
        ТекущаяПодстрока = СтрПолучитьСтроку(СтрокиПоЗапятым, Ном);
        Если ПустаяСтрока(ТекущаяПодстрока) Тогда
            Продолжить;
        КонецЕсли;
        
        СтрокиПоДефису = СтрЗаменить(ТекущаяПодстрока, "-", Символы.ПС);
        КоличествоДефисов = СтрЧислоСтрок(СтрокиПоДефису);
        
        Если КоличествоДефисов > 1 Тогда
            ЛеваяГраница  = Число(СтрПолучитьСтроку(СтрокиПоДефису, 1));
            ПраваяГраница = Число(СтрПолучитьСтроку(СтрокиПоДефису, 2));
            
            Для Индекс = ЛеваяГраница По ПраваяГраница Цикл
                Результат.Добавить(Индекс);
            КонецЦикла;
        Иначе
            Результат.Добавить(Число(ТекущаяПодстрока));
        КонецЕсли;
    КонецЦикла;
    
    Возврат Результат;
КонецФункции

Вариант 3. Использование БСП (Библиотеки Стандартных Подсистем)

В типовых конфигурациях 1С для работы со строками рекомендуется использовать функции общего назначения из БСП. Функция СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок позволяет безопасно разбить строку на массив элементов с автоматической обрезкой незначащих пробелов.


Функция РазобратьСтрокуЧерезБСП(Знач ВходнаяСтрока) Экспорт
    Результат = Новый Массив;
    
    Подстроки = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(ВходнаяСтрока, ",", Истина, Истина);
    Для Каждого Подстрока Из Подстроки Цикл
        ЧастиИнтервала = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(Подстрока, "-", Истина, Истина);
        
        Если ЧастиИнтервала.Количество() = 1 Тогда
            Результат.Добавить(Число(ЧастиИнтервала[0]));
        ИначеЕсли ЧастиИнтервала.Количество() = 2 Тогда
            От = Число(ЧастиИнтервала[0]);
            До = Число(ЧастиИнтервала[1]);
            Для Номер = От По До Цикл
                Результат.Добавить(Номер);
            КонецЦикла;
        КонецЕсли;
    КонецЦикла;
    
    Возврат Результат;
КонецФункции

Сортировка и удаление дубликатов

Выясним частую сопутствующую проблему: если пользователь передал пересекающиеся интервалы (например, "1-5, 3-7") или нарушил порядок ввода ("10, 2, 5"), результирующий массив может содержать повторяющиеся значения и не быть упорядоченным.

Так как у стандартного объекта Массив в 1С нет метода сортировки, для упорядочивания и устранения дубликатов удобно использовать вспомогательные коллекции:

  1. Через Соответствие: При добавлении элементов ключ соответствия автоматически гарантирует уникальность (Коллекция.Вставить(ЧисловоеЗначение, Истина)).
  2. Через СписокЗначений: Заполняем СписокЗначений и вызываем Список.СортироватьПоЗначению(НаправлениеСортировки.Возр).
  3. Через ТаблицуЗначений: Заполняем колонку с типом Число, вызываем ТЗ.Свернуть("НомерСтроки") и ТЗ.Сортировать("НомерСтроки Возр").

Важное предостережение: Избегайте использования вызовов через COMОбъект("VBScript.RegExp") и функцию Выполнить(). Использование COM-объектов нарушает кроссплатформенность конфигурации (код не сможет выполниться на сервере под управлением Linux или в веб-клиенте), а вызов Выполнить() создает потенциальную уязвимость для выполнения произвольного кода и заблокирован в безопасном режиме.

← На главную