При загрузке данных из внешних текстовых файлов (например, в формате CSV или выгрузок из сторонних учетных систем) часто возникает задача разбить строку на массив значений. Обычно элементы разделяются запятыми. Однако если среди полей есть наименования номенклатуры с техническими характеристиками (например, "Цепь рывковая двойная 2,5ммх60см"), запятая внутри строки воспринимается механизмом разбора как разделитель колонок. В результате целостность строки нарушается, а данные смещаются по колонкам.
Стандартный метод платформы СтрРазделить выполняет строгое разбиение по символу-разделителю без учета контекста и не умеет пропускать запятые, находящиеся внутри парных кавычек. Рассмотрим подходы к правильному разбору таких строк на чистом коде 1С и с использованием регулярных выражений.
Разберем наиболее универсальный и надежный вариант, работающий на встроенном языке 1С без использования сторонних библиотек и компонентов. Суть метода заключается в последовательном проходе по строке и отслеживании парных кавычек.
Рассмотрим пример процедуры, которая считывает элементы поочередно, корректно выделяя строки в кавычках и обычные значения (включая числа и пустые поля):
&НаКлиенте
Процедура РазобратьСтроку(Знач СтрокаВход)
// Добавляем завершающий разделитель для обработки последнего элемента
СтрокаВход = СтрокаВход + ",";
МассивВыход = Новый Массив;
Пока Не ПустаяСтрока(СтрокаВход) Цикл
Если Лев(СтрокаВход, 1) = """" Тогда
// Если элемент начинается с кавычки, ищем закрывающую кавычку
ПозЗакрывающейКавычки = СтрНайти(СтрокаВход, """",, 2);
Если ПозЗакрывающейКавычки > 0 Тогда
Элемент = Сред(СтрокаВход, 2, ПозЗакрывающейКавычки - 2);
МассивВыход.Добавить(Элемент);
// Отрезаем обработанную часть вместе со следующей за ней запятой
СтрокаВход = Прав(СтрокаВход, СтрДлина(СтрокаВход) - ПозЗакрывающейКавычки - 1);
Иначе
// Если закрывающая кавычка не найдена, прерываем обработку
Прервать;
КонецЕсли;
Иначе
// Поле без кавычек (число, дата или пустое значение)
ПозЗапятой = СтрНайти(СтрокаВход, ",",, 1);
Если ПозЗапятой > 0 Тогда
Элемент = СокрЛП(Лев(СтрокаВход, ПозЗапятой - 1));
МассивВыход.Добавить(Элемент);
СтрокаВход = Прав(СтрокаВход, СтрДлина(СтрокаВход) - ПозЗапятой);
Иначе
Прервать;
КонецЕсли;
КонецЕсли;
КонецЦикла;
// Результат содержат элементы в правильном порядке
КонецПроцедуры
Проанализируем работу этого алгоритма. Если очередное поле начинается с символа кавычки """", код ищет следующую кавычку и извлекает содержимое между ними целиком, игнорируя любые запятые внутри. Если элемент начинается без кавычки, поиск выполняется до ближайшей запятой.
Рассмотрим альтернативный способ: сначала разбить строку базовым методом или регулярным выражением по разделителю, а затем в цикле склеить те части, которые были ошибочно разделены внутри текста номенклатуры.
Сформулируем алгоритм склейки фрагментов:
Посмотрим на реализацию этого подхода:
Функция ВосстановитьМассивСтрок(МассивИсходный) Экспорт
Результат = Новый Массив;
НакопленныйЭлемент = "";
Склеиваем = Ложь;
Для Каждого Элемент Из МассивИсходный Цикл
Текст = СокрЛП(Элемент);
Если Склеиваем Тогда
НакопленныйЭлемент = НакопленныйЭлемент + "," + Текст;
Если Прав(Текст, 1) = """" Тогда
Результат.Добавить(СтрЗаменить(НакопленныйЭлемент, """", ""));
НакопленныйЭлемент = "";
Склеиваем = Ложь;
КонецЕсли;
Иначе
Если Лев(Текст, 1) = """" И Прав(Текст, 1) <> """" Тогда
НакопленныйЭлемент = Текст;
Склеиваем = Истина;
Иначе
Результат.Добавить(СтрЗаменить(Текст, """", ""));
КонецЕсли;
КонецЕсли;
КонецЦикла;
Возврат Результат;
КонецФункции
Для систем, работающих под управлением ОС Windows, разбор текстовой строки можно выполнить с использованием COM-объекта VBScript.RegExp.
Разберем шаблон регулярного выражения, позволяющий выделить текстовые фрагменты в кавычках или блоки символов без разделителя:
Функция РазложитьСтрокуRegExp(Знач СтрокаТекста, Разделитель = ",") Экспорт
RegExp = Новый COMОбъект("VBScript.RegExp");
RegExp.MultiLine = Ложь;
RegExp.Global = Истина;
RegExp.IgnoreCase = Ложь;
// Маска: ищет текст в кавычках ИЛИ последовательность символов без разделителя
RegExp.Pattern = """(.*?)""|([^\" + Разделитель + "]+)";
Matches = RegExp.Execute(СтрокаТекста);
Массив = Новый Массив;
Для Сч = 0 По Matches.Count - 1 Цикл
ЗначениеЭлемента = Matches.Item(Сч).Value;
// Очищаем значение от внешних кавычек
ЗначениеЭлемента = СтрЗаменить(ЗначениеЭлемента, """", "");
Массив.Добавить(ЗначениеЭлемента);
КонецЦикла;
Возврат Массив;
КонецФункции
Выясним преимущества и недостатки данного метода:
СтрНайтиПоРегулярномуВыражению).При организации загрузки данных из сторонних текстовых документов необходимо учитывать следующие важные моменты:
"Товар",0,,"4606949031820", где присутствуют две запятые подряд без значений между ними.""). При финальной очистке элементов массива заменяйте двойные кавычки "" на одиночные ".СокрЛП и удаляйте обрамляющие кавычки.