Разбор и разделение строк в 1С 8.3 на примерах

· 10 мин

Содержание

Чтобы разделить строку в 1С 8.3 на части, используют встроенную функцию СтрРазделить: она принимает исходную строку и символ-разделитель, а возвращает массив значений. Для большинства задач — разобрать строку с запятыми, табуляцией или точкой с запятой — этого достаточно, цикл с Найти и Сред писать не нужно.

Функция работает в платформе начиная с версии 8.3.6, поэтому в типовых конфигурациях (Бухгалтерия 3.0, ЗУП 3.1, УТ 11) она доступна без оговорок — и на клиенте, и на сервере, в общих модулях и в формах.

Сложнее становится, когда разделителей несколько, когда внутри данных встречаются кавычки (формат CSV) или когда результат нужно сразу разложить по колонкам таблицы значений. Эти случаи разберём отдельно — с готовым кодом, который можно скопировать и подставить свои данные.

Функция СтрРазделить: базовый разбор по разделителю

Синтаксис такой:

Массив = СтрРазделить(ИсходнаяСтрока, Разделитель, ВключатьПустые);
  • ИсходнаяСтрока — строка, которую разбиваем.
  • Разделитель — строка-разделитель (о ней ниже важная деталь).
  • ВключатьПустые — булево, по умолчанию Истина.

Простейший пример:

Массив = СтрРазделить("яблоко,груша,слива", ",");
// Массив[0] = "яблоко"
// Массив[1] = "груша"
// Массив[2] = "слива"

Функция всегда возвращает Массив, даже если разделитель в строке не встретился — тогда в массиве будет один элемент, равный всей исходной строке. Поэтому обращаться к Массив[0] безопасно, а вот к Массив[1] — только после проверки количества.

Элементы массива — это строки. Если в них лежат числа или даты, приводите тип явно: Число(Массив[2]), Дата(Массив[0]). Неявного преобразования здесь нет.

Параметр ВключатьПустые: куда пропадают элементы

Третий параметр решает, что делать с пустотой между двумя разделителями подряд:

// Истина (по умолчанию) — пустые попадают в результат
Массив = СтрРазделить("1,,3", ",", Истина);   // 3 элемента: "1", "", "3"

// Ложь — пустые отбрасываются
Массив = СтрРазделить("1,,3", ",", Ложь);      // 2 элемента: "1", "3"

Это частый источник ошибок. Если вы читаете строку CSV, где пустая ячейка — это нормальный пропуск значения, оставляйте Истина, иначе колонки «съедут». А если разбираете список тегов, где лишние запятые — мусор, ставьте Ложь.

Несколько разделителей сразу

Здесь кроется неочевидная, но полезная особенность: каждый символ строки-разделителя 1С рассматривает как самостоятельный разделитель. То есть передавать можно не один символ, а набор:

Массив = СтрРазделить("1,2;3 4", ",; ");
// Разбивает по запятой, точке с запятой И пробелу сразу
// Массив: "1", "2", "3", "4"

Строка ",; " — это не «разделитель из трёх символов», а три разных разделителя: запятая, точка с запятой, пробел. Это удобно, когда данные пришли из разных источников и разделитель «гуляет».

Типичный случай — список артикулов или кодов, который пользователь ввёл в поле вручную: кто-то разделяет запятыми, кто-то пробелами, кто-то и тем, и другим. Один вызов СтрРазделить(Ввод, ", ;" + Символы.ПС, Ложь) с параметром ВключатьПустые = Ложь вернёт чистый массив кодов без пустых элементов, как бы их ни разделили (запятая, пробел, точка с запятой или перенос строки).

Минус подхода — он не отличает «один пробел» от «пять пробелов». Между словами в "Иван Петров" получится несколько пустых элементов. Лечится это либо параметром ВключатьПустые = Ложь, либо предварительной заменой через СтрЗаменить, либо регулярным выражением (см. ниже).

Многосимвольный разделитель (например, " -> " целиком) функция СтрРазделить не поддерживает. Если нужно резать именно по последовательности символов, замените её сначала на один служебный символ через СтрЗаменить, а потом режьте по нему.

Разбор многострочного текста по строкам

Отдельная задача — разложить текст на строки (по переводам строки). Напрямую через СтрРазделить(Текст, Символы.ПС) это работает, но есть подвох: в Windows конец строки — это пара символов ВК + ПС (возврат каретки и перевод строки). Если передать их как разделители, между строками появятся пустые элементы.

Надёжнее — специализированные функции платформы:

Для Н = 1 По СтрЧислоСтрок(Текст) Цикл
    Строка = СтрПолучитьСтроку(Текст, Н);
    Сообщить(Строка);
КонецЦикла;
  • СтрЧислоСтрок(Текст) — сколько строк в тексте (нумерация с 1).
  • СтрПолучитьСтроку(Текст, Н) — вернуть строку с номером Н.

Эта пара корректно обрабатывает любые варианты перевода строки — и ПС, и ВК ПС, — не создавая пустых элементов. Для перебора строк текстового файла или многострочного поля формы это самый безопасный способ.

Если всё же хотите массив, сначала уберите возврат каретки:

Текст = СтрЗаменить(Текст, Символы.ВК, "");
Массив = СтрРазделить(Текст, Символы.ПС);

Когда разбираете большой текстовый файл, не загружайте его целиком в память — читайте построчно объектом ЧтениеТекста:

Чтение = Новый ЧтениеТекста(ПутьКФайлу, КодировкаТекста.UTF8);
Строка = Чтение.ПрочитатьСтроку();
Пока Строка <> Неопределено Цикл
    Поля = СтрРазделить(Строка, ";");
    // ... обработка одной строки файла
    Строка = Чтение.ПрочитатьСтроку();
КонецЦикла;
Чтение.Закрыть();

ПрочитатьСтроку сама отдаёт по одной строке и возвращает Неопределено в конце файла — переносы строк при этом уже отрезаны. Для выгрузок на десятки тысяч строк это экономит память и не упирается в ограничения формы.

Формат CSV: когда внутри данных есть кавычки

CSV коварен тем, что разделитель может встречаться внутри значения, если оно взято в кавычки:

Иванов;"Петров, Сергей";25

Здесь разделитель — точка с запятой, но запятая в "Петров, Сергей" — часть имени, а не разделитель полей. Прямой вызов СтрРазделить(Строка, ";") разобьёт строку неверно, если разделитель встречается ещё и внутри кавычек.

Готового CSV-парсера с учётом кавычек в платформе нет. Варианты:

  1. Если кавычки в данных не встречаются — обычный СтрРазделить по разделителю полей. Это 90% внутренних выгрузок.
  2. Если значения берутся в кавычки — разбирайте строку посимвольно, отслеживая флаг «мы внутри кавычек», и переключайте разделение только вне кавычек.
  3. Регулярное выражение — для устойчивого разбора по шаблону (следующий раздел).

Каркас ручного разбора с учётом кавычек:

Функция РазобратьСтрокуCSV(Строка, Разделитель = ";")
    Результат = Новый Массив;
    Поле = "";
    ВнутриКавычек = Ложь;
    Для Позиция = 1 По СтрДлина(Строка) Цикл
        Символ = Сред(Строка, Позиция, 1);
        Если Символ = """" Тогда
            ВнутриКавычек = НЕ ВнутриКавычек;
        ИначеЕсли Символ = Разделитель И НЕ ВнутриКавычек Тогда
            Результат.Добавить(Поле);
            Поле = "";
        Иначе
            Поле = Поле + Символ;
        КонецЕсли;
    КонецЦикла;
    Результат.Добавить(Поле); // последнее поле
    Возврат Результат;
КонецФункции

Двойные кавычки внутри кода 1С экранируются удвоением: """" — это строковый литерал из одной кавычки. По стандарту CSV удвоенная кавычка внутри значения тоже означает одну кавычку — при необходимости добавьте её обработку.

Как разложить строку сразу в таблицу значений

Когда каждая строка текста — это запись с несколькими полями, разумно собрать результат не в массив, а в таблицу значений: с ней удобнее работать дальше (сортировка, отбор, выгрузка в документ).

ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Фамилия");
ТЗ.Колонки.Добавить("Имя");
ТЗ.Колонки.Добавить("Возраст");

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

Три приёма, которые экономят отладку:

  • СокрЛП убирает пробелы по краям поля — после разбора они часто остаются.
  • Проверка Поля.Количество() страхует от обращения к несуществующему индексу: неполная строка не обрушит обработку, а будет пропущена.
  • Приведение Число(...) держите в последнюю очередь и только там, где уверены в формате, иначе на нечисловом значении будет исключение — оберните в Попытка, если данные грязные.

Тот же подход работает и для загрузки из массива структур, если вместо ТаблицаЗначений вы складываете каждую строку в Новый Структура.

Регулярные выражения для сложных разделителей

Регулярные выражения нужны, когда разделитель описывается не символом, а шаблоном: «любое количество пробелов», «запятая с возможными пробелами вокруг», «цифры, разделённые чем угодно нецифровым».

Начиная с платформы 8.3.23 в 1С появился встроенный объект РегулярноеВыражение. Он ищет совпадения по шаблону методом НайтиСовпадения — то есть вместо того, чтобы «резать по разделителю», можно наоборот «вытащить все нужные куски» по маске:

РегВыр = Новый РегулярноеВыражение("[^,;]+");
Совпадения = РегВыр.НайтиСовпадения("1, 2;3 ,4");
Для Каждого Совпадение Из Совпадения Цикл
    Сообщить(СокрЛП(Совпадение.Значение));
КонецЦикла;

Шаблон [^,;]+ означает «один или более символов, кроме запятой и точки с запятой» — то есть сами значения между разделителями. Такой подход устойчив к лишним пробелам и переменному набору разделителей.

Если платформа старше 8.3.23, тот же результат на Windows дают COM-объекты через VBScript.RegExp. Здесь удобна нормализация: заменить любой разделитель на один служебный, а дальше разбить обычным СтрРазделить.

РегВыр = Новый COMОбъект("VBScript.RegExp");
РегВыр.Pattern = "[;\t ]+"; // точка с запятой, табуляция, пробелы
РегВыр.Global = Истина;
Нормализованная = РегВыр.Replace(Строка, ",");
Массив = СтрРазделить(Нормализованная, ",");

COM-объект VBScript.RegExp работает только на Windows и требует клиента с доступом к COM. На сервере под Linux он недоступен — там используйте встроенный РегулярноеВыражение (8.3.23+) или ручной разбор. Поэтому в серверном коде на регулярные выражения через COM лучше не закладываться.

Для большинства задач регулярные выражения — избыточны: если разделитель фиксированный, СтрРазделить быстрее и читается проще. Доставайте регэкспы только тогда, когда шаблон действительно сложный.

Какой способ выбрать

Какой способ разбора строки подойдёт в вашем случае?

Разбор по подстроке и ручной цикл

Два случая, когда СтрРазделить не подходит: разделитель — это целая подстрока из нескольких символов (например, " => " или "||"), и работа на платформе старше 8.3.6, где функции ещё нет. Оба решает ручной цикл на СтрНайти и Сред:

Функция РазбитьПоПодстроке(Строка, Разделитель)
    Результат = Новый Массив;
    Позиция = СтрНайти(Строка, Разделитель);
    Пока Позиция > 0 Цикл
        Результат.Добавить(Лев(Строка, Позиция - 1));
        Строка = Сред(Строка, Позиция + СтрДлина(Разделитель));
        Позиция = СтрНайти(Строка, Разделитель);
    КонецЦикла;
    Результат.Добавить(Строка); // остаток после последнего разделителя
    Возврат Результат;
КонецФункции

Как это работает по шагам:

  1. СтрНайти возвращает позицию первого вхождения разделителя или 0, если его нет.
  2. Лев(Строка, Позиция - 1) отрезает всё до разделителя — это очередной элемент.
  3. Сред(Строка, Позиция + СтрДлина(Разделитель)) оставляет «хвост» после разделителя, и поиск повторяется уже в нём.
  4. Когда вхождений больше нет, в массив добавляется остаток.

Главное отличие от СтрРазделить — здесь разделителем выступает именно последовательность символов целиком, а не каждый символ по отдельности. Поэтому " => " режет строку по стрелке со всеми пробелами, а не по каждому пробелу.

На платформе 8.3.6 и новее для одиночного символа всё равно выбирайте СтрРазделить — встроенная функция обрабатывает строку за один проход и работает заметно быстрее цикла с пересозданием строки на каждой итерации. Ручной разбор держите только для многосимвольного разделителя и старых версий.

Частые ошибки при разборе строк

Проверьте перед запуском разбора
Выполнено: 0 / 5

Что ломает разбор чаще всего:

  • Обращение к Массив[1], когда элемент один. Если разделитель не встретился, в массиве ровно один элемент. Проверяйте Количество().
  • Ожидание числа, а в элементе — строка. Массив[0] + 1 даст склейку строк или ошибку. Нужен Число(Массив[0]).
  • Слетевшие колонки из-за пустых значений. Поставили ВключатьПустые = Ложь там, где пустая ячейка допустима, — и все поля после пропуска сдвинулись.
  • Пустые элементы между строками Windows-текста. Разбивка по Символы.ПС на тексте с ВК ПС даёт лишние пустышки. Используйте СтрЧислоСтрок/СтрПолучитьСтроку.

Частые вопросы

Как собрать строку обратно из массива?
Обратная функция — СтрСоединить(Массив, Разделитель). Например, СтрСоединить(Массив, "; ") склеит элементы через точку с запятой и пробел. Доступна с той же версии платформы, что и СтрРазделить.
Работает ли СтрРазделить на сервере и в фоновом задании?
Да. Это функция платформы, доступная в любом контексте исполнения — на клиенте, на сервере, в фоновых и регламентных заданиях, в общих модулях. Ограничений по месту вызова нет.
С какой версии платформы доступна функция?
СтрРазделить и СтрСоединить работают начиная с платформы 8.3.6. На более старых версиях (8.2, ранние 8.3) приходилось писать цикл с СтрНайти и Сред вручную.
Можно ли разбить строку по подстроке из нескольких символов?
Напрямую СтрРазделить этого не умеет — второй параметр он трактует как набор отдельных символов-разделителей. Сначала замените подстроку на один служебный символ через СтрЗаменить, затем режьте по нему.
Как убрать лишние пробелы после разбора?
Примените СокрЛП к каждому элементу — функция срезает пробелы и слева, и справа. Для массовой очистки удобно обойти массив циклом и перезаписать элементы.