В практике разработчика 1С часто возникает задача разбора текстовых строк, полученных из внешних источников (например, CSV-файлов, логов или результатов API-запросов). Типичный пример такой строки выглядит следующим образом: "MAIN"",""100002"",""RES"","""",""1,92". На первый взгляд, задача кажется тривиальной — достаточно разделить строку по разделителю кавычка-запятая-кавычка ",". Однако при попытке использовать стандартные платформенные инструменты разработчики часто сталкиваются с неожиданным поведением системы, когда результирующий массив заполняется множеством пустых кавычек, а важные данные (например, числа с запятой) разделяются некорректно.
В этой статье мы подробно разберем, почему стандартная функция СтрРазделить не подходит для решения этой задачи в исходном виде, как решить проблему с помощью встроенных механизмов Библиотеки Стандартных Подсистем (БСП), а также рассмотрим современные альтернативные подходы — использование нативных регулярных выражений и специализированного объекта ЧтениеCSV.
Рассмотрим попытку использования стандартной функции платформы 1С:
СтрокаИсточник = """MAIN"",""100002"",""RES"","""",""1,92""";
Результат = СтрРазделить(СтрокаИсточник, """,""", Истина);
При выполнении этого кода в массив попадает огромное количество пустых строк и отдельных кавычек, а число 1,92 разбивается на два разных элемента: 1 и 92. Почему так происходит?
Дело в фундаментальном отличии работы платформенного метода СтрРазделить от привычных функций разделения в других языках программирования. Платформенная функция СтрРазделить воспринимает параметр Разделитель не как единую неделимую подстроку, а как набор одиночных символов-разделителей. Передав в качестве разделителя строку ",", мы приказываем платформе разделять исходный текст везде, где встречается символ кавычки " ИЛИ символ запятой ,.
Поскольку в нашей исходной строке запятая встречается как в качестве разделителя полей, так и внутри числа 1,92, а кавычки обрамляют каждое поле, алгоритм начинает дробить строку по каждому из этих символов в отдельности. Это приводит к полному уничтожению структуры данных.
Для того чтобы разделить строку по многосимвольному разделителю как по единому целому, необходимо использовать функцию из состава Библиотеки Стандартных Подсистем (БСП). Этот метод гарантирует, что разделитель любой длины будет обработан корректно. Если же файлы поступают из различных источников, программа для сбора прайс-листов с почты, FTP, HTTP позволит автоматизировать их получение для последующей обработки.
Рассмотрим структуру и алгоритм работы функции РазложитьСтрокуВМассивПодстрок общего модуля СтроковыеФункцииКлиентСервер:
Функция РазложитьСтрокуВМассивПодстрок(Знач Значение, Знач Разделитель = ",", Знач ПропускатьПустыеСтроки = Неопределено, СокращатьНепечатаемыеСимволы = Ложь) Экспорт
// Если разделитель стандартный, оптимизируем работу через системную функцию
Если Разделитель = "," И ПропускатьПустыеСтроки = Неопределено И СокращатьНепечатаемыеСимволы Тогда
Результат = СтрРазделить(Значение, ",", Ложь);
Для Индекс = 0 По Результат.ВГраница() Цикл
Результат[Индекс] = СокрЛП(Результат[Индекс])
КонецЦикла;
Возврат Результат;
КонецЕсли;
Результат = Новый Массив;
// Обеспечение обратной совместимости
Если ПропускатьПустыеСтроки = Неопределено Тогда
ПропускатьПустыеСтроки = ?(Разделитель = " ", Истина, Ложь);
Если ПустаяСтрока(Значение) Тогда
Если Разделитель = " " Тогда
Результат.Добавить("");
КонецЕсли;
Возврат Результат;
КонецЕсли;
КонецЕсли;
// Основной цикл разделения строки по многосимвольному шаблону
Позиция = СтрНайти(Значение, Разделитель);
Пока Позиция > 0 Цикл
Подстрока = Лев(Значение, Позиция - 1);
Если Не ПропускатьПустыеСтроки Или Не ПустаяСтрока(Подстрока) Тогда
Если СокращатьНепечатаемыеСимволы Тогда
Результат.Добавить(СокрЛП(Подстрока));
Иначе
Результат.Добавить(Подстрока);
КонецЕсли;
КонецЕсли;
Значение = Сред(Значение, Позиция + СтрДлина(Разделитель));
Позиция = СтрНайти(Значение, Разделитель);
КонецЦикла;
// Добавление последнего фрагмента строки
Если Не ПропускатьПустыеСтроки Или Не ПустаяСтрока(Значение) Тогда
Если СокращатьНепечатаемыеСимволы Тогда
Результат.Добавить(СокрЛП(Значение));
Иначе
Результат.Добавить(Значение);
КонецЕсли;
КонецЕсли;
Возврат Результат;
КонецФункции
Функция последовательно ищет вхождение подстроки-разделителя целиком с помощью функции СтрНайти, вырезает левую часть и сдвигает указатель поиска на длину разделителя с помощью функции Сред. Это позволяет избежать ложных срабатываний по отдельным символам.
Применим этот метод к нашей задаче. Перед разделением нам также потребуется очистить крайние кавычки исходной строки:
// Исходная строка: "MAIN"",""100002"",""RES"","""",""1,92"
СтрокаИсточник = """MAIN"",""100002"",""RES"","""",""1,92""";
// Удаляем крайние кавычки, чтобы первый и последний элементы не содержали лишних символов
Если Лев(СтрокаИсточник, 1) = """" Тогда
СтрокаИсточник = Сред(СтрокаИсточник, 2);
КонецЕсли;
Если Прав(СтрокаИсточник, 1) = """" Тогда
СтрокаИсточник = Лев(СтрокаИсточник, СтрДлина(СтрокаИсточник) - 1);
КонецЕсли;
// Теперь разделителем выступает строка из трех символов: ","
Разделитель = """,""";
МассивРезультат = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(СтрокаИсточник, Разделитель, Ложь);
// Проверяем результат работы
Для Каждого Элемент Из МассивРезультат Цикл
Сообщить(Элемент);
КонецЦикла;
В результате выполнения данного алгоритма мы получим чистый массив со следующими значениями: MAIN, 100002, RES, пустая строка "" и дробное число в виде строки 1,92. Задача успешно решена!
Долгое время в среде разработчиков 1С велись споры об отсутствии встроенного механизма регулярных выражений. Ранее приходилось использовать COM-объект VBScript.RegExp, который работал исключительно под управлением ОС Windows и значительно снижал производительность системы при частых вызовах.
Начиная с версии платформы 8.3.23, в 1С появилась полноценная кроссплатформенная поддержка регулярных выражений на уровне ядра (стандарт ICU). Мы можем решить задачу автора изящно и современно, используя функцию СтрНайтиВсеПоРегулярномуВыражению.
Разберем по шагам, как составить регулярное выражение для извлечения значений, находящихся внутри кавычек. Шаблон регулярного выражения будет выглядеть так: [^",]+ или, если нам нужно строго учитывать пустые значения между разделителями, мы можем находить фрагменты, ограниченные кавычками: (?<=")[^"]*(?=").
Посмотрим на пример практической реализации:
СтрокаИсточник = """MAIN"",""100002"",""RES"","""",""1,92""";
ШаблонRegExp = "(?<="")[^""]*(?="")"; // Ищет любые символы (включая пустые), окруженные кавычками
РезультатыПоиска = СтрНайтиВсеПоРегулярномуВыражению(СтрокаИсточник, ШаблонRegExp);
МассивРезультат = Новый Массив;
Для Каждого Результат Из РезультатыПоиска Цикл
// Исключаем из результатов сами запятые-разделители, которые могли попасть в выборку
ТекстовоеЗначение = Сред(СтрокаИсточник, Результат.НачальнаяПозиция, Результат.Длина);
Если ТекстовоеЗначение <> "," Тогда
МассивРезультат.Добавить(ТекстовоеЗначение);
КонецЕсли;
КонецЦикла;
// Выводим полученный массив в консоль
Для Каждого Значение Из МассивРезультат Цикл
Сообщить("Элемент: " + Значение);
КонецЦикла;
Преимущества использования регулярных выражений в 1С:
Строка вида "MAIN"",""100002"",""RES"","""",""1,92" представляет собой классическую запись в формате CSV (Comma-Separated Values), где поля разделены запятыми, а текстовые блоки экранированы двойными кавычками. Платформа 1С предоставляет мощный встроенный инструмент для работы с такими структурами данных — объект ЧтениеCSV.
Использование этого объекта позволяет избежать написания собственных парсеров строк и гарантирует корректную обработку любых спецификаций стандарта CSV (включая переносы строк внутри полей и экранирование кавычек). При работе с внешними площадками для загрузки отчётов о продажах маркетплейсов в БП 3 из Excel часто применяются готовые инструменты, избавляющие от необходимости ручного написания кода парсера.
Рассмотрим пример использования ЧтениеCSV для разбора одиночной строки:
СтрокаИсточник = """MAIN"",""100002"",""RES"","""",""1,92""";
// Инициализируем объект чтения CSV
ЧтениеДанных = Новый ЧтениеCSV;
// Настраиваем параметры чтения: разделитель - запятая, символ маскировки - кавычка
ПараметрыЧтения = ПараметрыЧтенияCSV();
ПараметрыЧтения.РазделительПолей = ",";
ПараметрыЧтения.СимволМаскировкиПолей = """";
// Открываем чтение непосредственно из строки
ЧтениеДанных.ОткрытьСтроку(СтрокаИсточник, ПараметрыЧтения);
// Считываем массив полей строки
МассивРезультат = ЧтениеДанных.ПрочитатьСтроку();
ЧтениеДанных.Закрыть();
// Выводим результат разбора в окно сообщений
Если МассивРезультат <> Неопределено Тогда
Для Каждого Индекс Из МассивРезультат Цикл
Сообщить("Получено поле: " + Индекс);
КонецЦикла;
КонецЕсли;
Этот способ является наиболее предпочтительным и отказоустойчивым с точки зрения стандартов разработки 1С. Платформа берет на себя всю рутинную работу по очистке служебных символов, удалению маскировочных кавычек и сохранению целостности данных (таких как дробная часть чисел).
Для того чтобы выбрать наиболее подходящий инструмент для вашего проекта, проанализируем рассмотренные решения по ключевым критериям:
Изучив данные подходы, вы сможете легко справляться с любыми задачами по обработке сложных текстовых строк в 1С, выбирая наиболее эффективный и лаконичный способ реализации.