Разбор и разделение строк в 1С 8.3 на примерах
Содержание
Чтобы разделить строку в 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-парсера с учётом кавычек в платформе нет. Варианты:
- Если кавычки в данных не встречаются — обычный
СтрРазделитьпо разделителю полей. Это 90% внутренних выгрузок. - Если значения берутся в кавычки — разбирайте строку посимвольно, отслеживая флаг «мы внутри кавычек», и переключайте разделение только вне кавычек.
- Регулярное выражение — для устойчивого разбора по шаблону (следующий раздел).
Каркас ручного разбора с учётом кавычек:
Функция РазобратьСтроку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.23) и метод НайтиСовпадения.Разбор по подстроке и ручной цикл
Два случая, когда СтрРазделить не подходит: разделитель — это целая подстрока из нескольких символов (например, " => " или "||"), и работа на платформе старше 8.3.6, где функции ещё нет. Оба решает ручной цикл на СтрНайти и Сред:
Функция РазбитьПоПодстроке(Строка, Разделитель)
Результат = Новый Массив;
Позиция = СтрНайти(Строка, Разделитель);
Пока Позиция > 0 Цикл
Результат.Добавить(Лев(Строка, Позиция - 1));
Строка = Сред(Строка, Позиция + СтрДлина(Разделитель));
Позиция = СтрНайти(Строка, Разделитель);
КонецЦикла;
Результат.Добавить(Строка); // остаток после последнего разделителя
Возврат Результат;
КонецФункции
Как это работает по шагам:
СтрНайтивозвращает позицию первого вхождения разделителя или0, если его нет.Лев(Строка, Позиция - 1)отрезает всё до разделителя — это очередной элемент.Сред(Строка, Позиция + СтрДлина(Разделитель))оставляет «хвост» после разделителя, и поиск повторяется уже в нём.- Когда вхождений больше нет, в массив добавляется остаток.
Главное отличие от СтрРазделить — здесь разделителем выступает именно последовательность символов целиком, а не каждый символ по отдельности. Поэтому " => " режет строку по стрелке со всеми пробелами, а не по каждому пробелу.
На платформе 8.3.6 и новее для одиночного символа всё равно выбирайте СтрРазделить — встроенная функция обрабатывает строку за один проход и работает заметно быстрее цикла с пересозданием строки на каждой итерации. Ручной разбор держите только для многосимвольного разделителя и старых версий.
Частые ошибки при разборе строк
Что ломает разбор чаще всего:
- Обращение к
Массив[1], когда элемент один. Если разделитель не встретился, в массиве ровно один элемент. ПроверяйтеКоличество(). - Ожидание числа, а в элементе — строка.
Массив[0] + 1даст склейку строк или ошибку. НуженЧисло(Массив[0]). - Слетевшие колонки из-за пустых значений. Поставили
ВключатьПустые = Ложьтам, где пустая ячейка допустима, — и все поля после пропуска сдвинулись. - Пустые элементы между строками Windows-текста. Разбивка по
Символы.ПСна тексте сВК ПСдаёт лишние пустышки. ИспользуйтеСтрЧислоСтрок/СтрПолучитьСтроку.
Частые вопросы
Как собрать строку обратно из массива?
СтрСоединить(Массив, Разделитель). Например, СтрСоединить(Массив, "; ") склеит элементы через точку с запятой и пробел. Доступна с той же версии платформы, что и СтрРазделить.Работает ли СтрРазделить на сервере и в фоновом задании?
С какой версии платформы доступна функция?
СтрРазделить и СтрСоединить работают начиная с платформы 8.3.6. На более старых версиях (8.2, ранние 8.3) приходилось писать цикл с СтрНайти и Сред вручную.Можно ли разбить строку по подстроке из нескольких символов?
СтрРазделить этого не умеет — второй параметр он трактует как набор отдельных символов-разделителей. Сначала замените подстроку на один служебный символ через СтрЗаменить, затем режьте по нему.Как убрать лишние пробелы после разбора?
СокрЛП к каждому элементу — функция срезает пробелы и слева, и справа. Для массовой очистки удобно обойти массив циклом и перезаписать элементы.