Всем привет!
Есть задача разобрать текстовый файл, в строках которого идут данные табличной части документа.
Как видно, элементы разделены запятыми. И не составляет труда с помощью регулярных выражений разобрать строку в массив.
Но проблема в том, что в некоторых случаях в наименовании товара (одна из частей строки) встречается запятая, которая является разделителем. И получается, что строка разбивается, хотя это не нужно.
Как-то можно выкрутиться из этого? Не хватает мне опыта (

"@НачТовар@","Р2560 Цепь рывковая двойная 2,5ммх60см (SHP 2560)","00000851",1,"шт",1,150.9,150.9,"00000851 ","Р2560 Цепь рывковая двойная 2,5ммх60см (SHP 2560)",0,"4606949031820","@КонТовар@"
---
Попробуй так:

```1c
    RegExp.Pattern = "\"(.*?)(?:\"|$)|([^\" + Разделитель +"]+)";
```
---
в (29) ошибочка закралась, в наименовании запятая затиралась, подправил. Проверил: даже если в наименовании будет несколько запятых подряд, то все норм. Единственное, если между разделителями ничего не будет, например вот так:
"Тут наименование",0,,"ТутШК"
то в массив пустой элемент не попадет. Если что, просто подправьте проверку на пустую строку
---
запятую, которая находится внутри кавычек не учитывать
---
Как это сделать?

Вот мой код.

```1c
    Процедура ФайлЗагрузкиНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)

    СтандартнаяОбработка = Ложь;
    ДиалогВыбораФайла = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
    ДиалогВыбораФайла.Заголовок = "Выбрать файл для загрузки";
    ДиалогВыбораФайла.Фильтр = "(*.txt)|*.txt|";
    Если ДиалогВыбораФайла.Выбрать() Тогда
    ФайлЗагрузки = ДиалогВыбораФайла.ПолноеИмяФайла;
    //-----------------------------------------------------
    мСтрокФайла = Новый Массив();
    Файл = Новый ЧтениеТекста(ФайлЗагрузки);

    //прочитать строку считывает одну строку из файла
    //если достигнут конец файла, то возвращается значение НЕОПРЕДЕЛЕНО
    Строка = Файл.ПрочитатьСтроку();

    //а не был ли файл пуст?
    Если Строка <> Неопределено Тогда
    мСтрокФайла.Добавить(Строка);
    КонецЕсли;

    //цикл пока чтение строки не вернет НЕОПРЕДЕЛЕНО
    //внутри цикла повторяем чтение
    Пока Строка <> Неопределено Цикл

    Строка = Файл.ПрочитатьСтроку();
    Если Строка <> Неопределено Тогда

    мСтрокФайла.Добавить(Строка);
    МассивЗначенийТекСтроки = РазложитьСтрокуВМассив(Строка,",");

    // Очистим от кавычек и пробелов
    Для Сч = 0 по МассивЗначенийТекСтроки.ВГраница() Цикл
    МассивЗначенийТекСтроки[Сч] = СтрЗаменить(МассивЗначенийТекСтроки[Сч],"",");
    КонецЦикла;

    // добавим новую строку в табличную часть
    НоваяСтрокаТЧ = Объект.Таблица.Добавить();
    НоваяСтрокаТЧ.КолонкаНоменклатура = МассивЗначенийТекСтроки[1];
    НоваяСтрокаТЧ.КолонкаКоличество = МассивЗначенийТекСтроки[5];
    НоваяСтрокаТЧ.КолонкаЦена = МассивЗначенийТекСтроки[6];
    НоваяСтрокаТЧ.КолонкаСумма = МассивЗначенийТекСтроки[7];
    НоваяСтрокаТЧ.КолонкаАртикул = МассивЗначенийТекСтроки[2];
    НоваяСтрокаТЧ.КолонкаШтрихкод = МассивЗначенийТекСтроки[11];

    КонецЕсли;

    КонецЦикла;
    Файл.Закрыть();
    //-----------------------------------------------------

    КонецЕсли;

    КонецПроцедуры
```
---
а вот код разложения строки

```1c
    Функция РазложитьСтрокуВМассив(Строка, Разделитель = ",") Экспорт
    RegExp = Новый COMОбъект("VBScript.RegExp"); // создаем объект для работы с регулярными выражениями
    //Параметры:
    RegExp.MultiLine = Ложь; // истина — текст многострочный, ложь — одна строка
    RegExp.Global = Истина; // истина — поиск по всей строке, ложь — до первого совпадения
    RegExp.IgnoreCase = Ложь; // истина — игнорировать регистр строки при поиске
    //Разбор строки вида 1,СЛОВО,(1+2); Маска для разделителя ',' [^\,]*"
    RegExp.Pattern = "[^\" + Разделитель + "]+";
    Matches = RegExp.Execute (Строка);
    Массив = Новый Массив;
    Для Сч = 0 По Matches.Count - 1 Цикл
    Массив.Добавить(Matches.Item(Сч).Value);
    КонецЦикла;
    RegExp = Неопределено;
    Возврат Массив;
    КонецФункции
```
---
зачем так сложно

```1c
    Разделитель=",";
    мЗначенийстроки=ЗначениеИзСтрокиВнутр("{"#",51e7a0d2-530b-11d4-b98a-008048da3034,{0,{"S","" + СтрЗаменить(СтрЗаменить(ТабДок.ПолучитьСтроку(Ё), "", """), Разделитель, ""},{"S","") + ""}}}");
```
---
Разделитель="","" К сожалению, не прокатит - там есть числовые параметры, без кавычек.

(8) Аналогично.
---
(11) а сорри невнимательно прочитал текст
---
строку нужно "поедать" по-словно. начинаем анализировать первое слово. если первый символ кавычка, то "съедаем" строку до следующей кавычки, иначе до [следующей] запятой. и так "поедаем" строку до конца.
---
Только сейчас посмотрел на код, объединять подстроки можно еще на этапе формирования массива:

```1c
    Массив = Новый Массив;
    СоставнойЭлемент=";
    Для Сч = 0 По Matches.Count - 1 Цикл
    Элемент=Matches.Item(Сч).Value;
    Если Лев(СоставнойЭлемент,1)="" И Прав(СоставнойЭлемент,1)<>"" Тогда // есть незавершенная строка
    СоставнойЭлемент=СоставнойЭлемент+","+Элемент;
    Если Прав(СоставнойЭлемент,1)="" Тогда // строка завершилась
    Массив.Добавить(СоставнойЭлемент);
    СоставнойЭлемент=";
    КонецЕсли;
    ИначеЕсли Лев(Элемент,1)="" И Прав(СоставнойЭлемент,1)<>"" Тогда // новая незавершенная строка
    СоставнойЭлемент=Элемент;
    Иначе
    Массив.Добавить(Элемент);
    КонецЕсли;
    КонецЦикла;
```
---
```1c
    &НаКлиенте
    Процедура Команда1(Команда)
    СтрокаВход = СтрокаВход + ",";
    МассивВыход = Новый Массив;
    Пока СтрДлина(СтрокаВход) > 0 Цикл
    с1 = Лев(СтрокаВход, 1);
    Если с1 = "" Тогда
    с2 = СтрНайти(СтрокаВход, "",,2,)+1;
    Иначе
    с2 = СтрНайти(СтрокаВход, ",",,2,);
    КонецЕсли;
    МассивВыход.Добавить(Лев(СтрокаВход,с2-1));
    СтрокаВход = Прав(СтрокаВход, СтрДлина(СтрокаВход)-с2);
    КонецЦикла;
    СтрокаВыход = СтрСоединить(МассивВыход,Символы.ПС)
    КонецПроцедуры
```

"@НачТовар@"
"Р2560 Цепь рывковая двойная 2,5ммх60см (SHP 2560)"
"00000851"
1
"шт"
1
150.9
150.9
"00000851 "
"Р2560 Цепь рывковая двойная 2,5ммх60см (SHP 2560)"
0
"4606949031820"
"@КонТовар@"
---
Вот же выше (18) предложил самый просто и эффективный вариант, чем не устраивает?

```1c
    &НаКлиенте
    Процедура Команда1(Команда)
    СтрокаВход = СтрокаВход + ",";
    МассивВыход = Новый Массив;
    Пока СтрДлина(СтрокаВход) > 0 Цикл
    с1 = Лев(СтрокаВход, 1);
    Если с1 = "" Тогда
    с2 = СтрНайти(СтрокаВход, "",,2,)+1;
    Иначе
    с2 = СтрНайти(СтрокаВход, ",",,2,);
    КонецЕсли;
    МассивВыход.Добавить(Лев(СтрокаВход,с2-1));
    СтрокаВход = Прав(СтрокаВход, СтрДлина(СтрокаВход)-с2);
    КонецЦикла;
    СтрокаВыход = СтрСоединить(МассивВыход,Символы.ПС)
    КонецПроцедуры
```
---
Если без отбрасывания кавычек (как в оригинале), то можно упростить:

```1c
    RegExp.Pattern = "".*?"|[^\" + Разделитель + "]+";
```
---
теперь и для строк с пустыми значениями, типа
"Тут наименование",0,,"ТутШК"

```1c
    СтрокаВход = СтрокаВход + ",";
    МассивВыход = Новый Массив;
    Пока Не ПустаяСтрока(СтрокаВход) Цикл
    Если Лев(СтрокаВход, 1) = "" Тогда
    с2 = СтрНайти(СтрокаВход, "",,2,);
    МассивВыход.Добавить(Лев(СтрокаВход,с2));
    СтрокаВход = Прав(СтрокаВход, СтрДлина(СтрокаВход)-с2-1);
    Иначе
    с2 = СтрНайти(СтрокаВход, ",",,1,);
    МассивВыход.Добавить(Лев(СтрокаВход,с2-1));
    СтрокаВход = Прав(СтрокаВход, СтрДлина(СтрокаВход)-с2);
    КонецЕсли;
    КонецЦикла;
    СтрокаВыход = СтрСоединить(МассивВыход,Символы.ПС)
```
---
При разборе строки нужно не разбивать строки, которые находятся внутри кавычек.
---
в (2) и (3) приведены в принципе правильные рецепты, но вот как объяснить это движку 1С - вопрос остался открытым.

Предлагаю способ: разбиваем строку в массив по запятым, потом в цикле обрабатываем массив по алгоритму: если элемент массива начинается с кавычки и не заканчивается ею, то объединяем его со следующим элементом, т.к. это разбитая строка.
---
Да, вариант! Как приеду с работы, надо попробовать так и сделать.
---
Только еще дополнение: объединять подстроки из массива надо тоже в цикле (вложенном), до тех пор, пока строка не будет начинаться и заканчиваться кавычкой - это на случай, если в строке окажется больше одной запятой и ее разобьет на три или больше элемента.
---
Функция СтрРазделить, в качестве разделителя использовать саму кавычку ", элемент массива с запятой отбросить
---
Решение в лоб за 5 минут на коленке.
Прикрепил обработку к ответу
---
не взлетело, см. (9).
---
Вы обработку смотрели?
у меня не Разделитель="",""
я же прикрепил скриншот результата, что там не так?
По ТЗ из шапки сделано слово в слово
---
скриншот результата, что там не так? Вот это:

1,150.9,150.9

Это должно быть три элемента массива, а не один.
---
так и надо писать в ТЗ.
2 минуты делов то поправить было
---
Непонятно, зачем такие сложности? Кто вообще в здравом уме использует разделители, которые используются в строках? А если там еще что всплывет? Две, три запятые? Будем ИИ писать, чтобы строку разобрать?) Все решение:изменить разделитель, а в 1С использовать стандартный метод СтрРазделить, если платформа свежая
---
А так, в качестве разделителя можно сочетание [,"] использовать, но потом у элементов дополнительно кавычки удалять
---
[",] такую конструкцию потом удалять, но все равно это не решит задачу полностью, ибо там надо еще и каждую строку постобработать. ибо есть еще и такая конструкция ,1,150.9,150.9
---
повнимательней посмотрел, там числовые значения без кавычек, так что не прокатит...
---
ох какой ажиотаж получить вознаграждение =))) Вообще файл похож на CSV который сделали TXT с разделителем в виде запятой. Попробуйте переименовать файл в расширение CSV и открыть в EXCEL он по идее сам разобьет эту строку по колонкам. Если такой варик прокатит то потом просто работаем с ним как с xls файлом.
---
кому нужно вознаграждение за такую задачу ))) это же чисто спортивный интерес.
---
переименовать файл в расширение CSV и открыть в EXCEL он по идее сам разобьет эту строку по колонкам. Если такой варик прокатит то потом просто работаем с ним как с xls файлом. Гм! Такой "варик" в сочетании с ником почему-то напомнил старинный анекдот. :)
---
А вообще начать нужно было с того чтоб узнать из какой учетной системы этот файл выгрузили!!!

(27) А анекдот расскажешь?
---
А анекдот расскажешь? Зачем? Там ссылка на него.

Но ваша невнимательность его лишний раз подтверждает... :)
---
Сообщение было скрыто модератором.
---
Есть простое решение:
Проход1 - заменяем запятые внутри кавычек на что-нибудь уникальное
Проход2 - идеально делим по оставшимся разделителям ","
Проход3 - возвращаем запятые из прохода1 на место

Не быстро, но надежно. Многократно проверено руками в EXСEL
---
Попробуй так:

```1c
    RegExp.Pattern = "\"(.*?)(?:\"|$)|([^\" + Разделитель +"]+)";
```
---
RegExp.Pattern = "\""(.*?)(?:\""|$)|([^\" + Разделитель +"]+)";

Похоже, это самый изящный вариант.
Вот что бывает, когда нет образования программиста как в моем случае.

Да, клиент вынужден пользоваться такой структурой исходных файлов. Ему поставщик присылает накладные в таком виде с запятыми из какой-то семерочной одинэсины. Стоит задача загрузить файл в ТЗ и и загрузить все в документ поступления, найдя соответствующую номенклатуру.
Задача простая, только все уперлось в эти запятые)

Я всех благодарю за отзывчивость!
---
Разрабов поставщика на кол, 7ку в топку!)) А по сути залезть в код и поменять разделитель - дело 5 минут, если, конечно, не "профессионалы" писали
---
ну, знаешь, дело-то 5 минут. но труднее убедить, что 7.7 в 2018 году это как бы перебор)
я сегодня одному клиенту по его просьбе делал пустую базу бухгалтерии 7.7. так у него винда XP стоит! говорит - ну а зачем оно мне надо? мне только счет выписать...

поэтому касаемо задачи с запятой - мне надо было сделать, а не доказывать клиенту, что это неправильно и т.д.
---
Сообщение было скрыто модератором.
---
Сообщение было скрыто модератором.
---
Все, разобрался! Спасибо еще раз! Я по ошибке не тот по счету элемент массива подставлял в ТЧ, поэтому получал не тот результат. А строки Ваше регулярное выражение разбирает как надо.
---
Конкретно под вашу строку:

```1c
    &НаКлиенте
    Процедура Разложить(Команда)

    НоваяСтрока = СТрЗаменить(ИсходнаяСтрока, ""@НачТовар@",", ");
    НоваяСтрока = СТрЗаменить(НоваяСтрока, ","@КонТовар@"", ");

    Массив = Новый Массив;
    ОставшаясяСтрока = СокрЛП(НоваяСтрока);
    ПОка Не ПустаяСтрока(ОставшаясяСтрока) Цикл
    ПервыйСимвол = Лев(ОставшаясяСтрока, 1);
    ВторойСимвол = Сред(ОставшаясяСтрока, 2, 1);
    Если ВторойСимвол = "" Тогда
    ОставшаясяСтрока = Прав(ОставшаясяСтрока, СтрДлина(ОставшаясяСтрока)-1);
    ПервыйСимвол = "";
    КонецЕсли;
    ДобавитьЭлемент(ОставшаясяСтрока, Массив, ПервыйСимвол);
    КонецЦикла;

    Список.ЗагрузитьЗначения(Массив);

    КонецПроцедуры

    Процедура ДобавитьЭлемент(ОставшаясяСтрока, Массив, Символ)

    Дл = СтрДлина(ОставшаясяСтрока);
    Если Символ = "," Или Символ = "" Тогда
    ОставшаясяСтрока = Прав(ОставшаясяСтрока, Дл-1);
    КонецЕсли;
    ДлинаНов = СтрДлина(ОставшаясяСтрока);
    Если Символ = "" Или Символ = "," Тогда
    Позиция = СтрНайти(ОставшаясяСтрока, Символ);
    Иначе
    Позиция = СтрНайти(ОставшаясяСтрока, ",");
    КонецЕсли;
    НовЭл = СокрЛП(Лев(ОставшаясяСтрока, Позиция-1));
    НовЭл = СтрЗаменить(НовЭл, "", ");
    НовЭл = СтрЗаменить(НовЭл, ",", ");
    Если Не ПустаяСтрока(НовЭл) Тогда
    Массив.Добавить(НовЭл);
    КонецЕсли;
    ОставшаясяСтрока = СокрЛП(Прав(ОставшаясяСтрока, ДлинаНов-Позиция));

    КонецПроцедуры
```
---
в (29) ошибочка закралась, в наименовании запятая затиралась, подправил. Проверил: даже если в наименовании будет несколько запятых подряд, то все норм. Единственное, если между разделителями ничего не будет, например вот так:
"Тут наименование",0,,"ТутШК"
то в массив пустой элемент не попадет. Если что, просто подправьте проверку на пустую строку
---
Алексей, спасибо и Вам! Я сейчас пытался с помощью регулярного выражения сделать задачу. Вроде бы все преобразуется, а потом пригляделся, а там все вразнобой - т.е. вообще не в той последовательности идут данные. Видимо в рег.выражении ошибка все-таки. А я надеялся на такое красивое решение.
Поэтому сейчас прибегнул к Вашему решению.
---
Дай для теста входные данные, где вразнобой.
ЗЫ. Я б вернул наградные, если другое решение больше подходит - не проблема :)
---
Да ну брось ты, еще чего. У меня уже контакты плавятся) Я сейчас ищу ошибку. Кажется понимаю в чем дело. У меня же еще свои манипуляции идут с ТабЗн результата. Так что моя вина скорее всего. Как закончу отпишусь.
---
На примере выложенной обработки и файлов я вроде ошибки не вижу. Кроме той, что количество не из той колонки тянется :) И еще первая строка там пропускается.
---
Да, все верно. Вот с первой строкой я налажал. Скопировал кусок кода под себя, а там косяк.
---
В общем, все! И твой вариант, и вариант Алексея рабочие. Все непонятки мои из-за моих же ошибок (тупости).
Спасибо еще раз!
---
тут перестарались =)
```1c
    Если Символ = "" Или Символ = "," Тогда
    Позиция = СтрНайти(ОставшаясяСтрока, Символ);
    Иначе
    Позиция = СтрНайти(ОставшаясяСтрока, ",");
    КонецЕсли;
```
---
не, там может 1й символ быть цифрой, тогда нужно искать запятую) может и изящнее можно, делалось на коленке)
---
МТС в свое время рассылал CSV файлы с расшифровкой затрат на связь. Так вот они тоже приняли "," разделителем, но в тексте встречалась "," и ни каких кавычек не было. Это был полный угар такое разбирать.
---
А мне вспомнился другой анекдот (вернее, правда жизни): "если для решения своей проблемы вы решили использовать регулярные выражения, то теперь у вас две проблемы" :)
---
Я выложу исходник своей обработки и файлы. Может кому пригодится, мало ли.
---
Алексея вариант лучше на перспективу (хоть я его и не смотрел).
Я хоть и поправил регулярку, но вообще - использование внешних компонент без явной на то необходимости в 1С является плохим стилем. В данном случае идет явная завязка на windows, а если в очередной версии винды этот ком-объект выкинут, то и на винде работать перестанет.
Да и не нужны в 1С регулярки. Не так уж часто парсить нужно и в большинстве случаев парсинг простой.