Чтение CSV по правилам RFC 4180

09.07.24

Разработка - Универсальные функции

Что такое CSV? Описание правил формата RFC4180 и пара функций чтения/записи CSV текста в ТЗ согласно этим рекомендациям (с экранированием и _поддержкой многострочных полей_).

Скачать файл

ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.

Наименование По подписке [?] Купить один файл
ПреобразованиеCSVвТЗ.epf
.epf 13,75Kb ver:KAV2 update
34
34 Скачать (1 SM) Купить за 1 850 руб.

По мотивам... Перевод документа с ietf.org:

Правило №1: Каждая запись (record) начинается с новой строки. (CRLF, #13#10, U+000D U+000A)

1. Each record is located on a separate line, delimited by a line
   break (CRLF).  For example:

   aaa,bbb,ccc CRLF
   zzz,yyy,xxx CRLF

Правило №2: Последня запись может оканчиваться переносом строки.

2. The last record in the file may or may not have an ending line
   break.  For example:

   aaa,bbb,ccc CRLF
   zzz,yyy,xxx

Правило №3: Опционально первая строка может являться заголовком, содержащим имена колонок.

3. There maybe an optional header line appearing as the first line
   of the file with the same format as normal record lines.  This
   header will contain names corresponding to the fields in the file
   and should contain the same number of fields as the records in
   the rest of the file (the presence or absence of the header line
   should be indicated via the optional "header" parameter of this
   MIME type).  For example:

   field_name,field_name,field_name CRLF
   aaa,bbb,ccc CRLF
   zzz,yyy,xxx CRLF

Правило №4: Поля разделены запятыми (разделителем). Заждая запись имеет одинаковое количество полей. Пробелы являются частью полей и не должны игнорироваться. После последнего поля не может быть запятой.

4. Within the header and each record, there may be one or more
   fields, separated by commas.  Each line should contain the same
   number of fields throughout the file.  Spaces are considered part
   of a field and should not be ignored.  The last field in the
   record must not be followed by a comma.  For example:

   aaa,bbb,ccc

Правило №5: Каждое поле может быть заключено в двойные кавычки. Если поле не заключено в двойные кавычки, то внутри уже не может находится сивол двойных кавычек. (По-умолчанию поле заключается в кавычки, если требуется экранирование, см. правило 6)

5. Each field may or may not be enclosed in double quotes (however
   some programs, such as Microsoft Excel, do not use double quotes
   at all).  If fields are not enclosed with double quotes, then
   double quotes may not appear inside the fields.  For example:

   "aaa","bbb","ccc" CRLF
   zzz,yyy,xxx

Правило №6: Поля, содержащие символ переноса строки, двойные кавычки и запятые должны быть заключены в двойные кавычки. (Поле может быть многострочным и содержать символ разделителя)

6. Fields containing line breaks (CRLF), double quotes, and commas
   should be enclosed in double-quotes.  For example:

   "aaa","b CRLF
   bb","ccc" CRLF
   zzz,yyy,xxx

Правило №7: Если поле заключено в двойные кавычки, то кавычки внутри поля должны быть экранированы предшествующими кавычками.

7. If double-quotes are used to enclose fields, then a double-quote
   appearing inside a field must be escaped by preceding it with
   another double quote.  For example:

   "aaa","b""bb","ccc"

ABNF грамматика

   file = [header CRLF] record *(CRLF record) [CRLF] 
   header = name *(COMMA name) 
   record = field *(COMMA field) 
   name = field 
   field = (escaped / non-escaped) 
   escaped = DQUOTE *(TEXTDATA / COMMA / CR / LF / 2DQUOTE) DQUOTE 
   non-escaped = *TEXTDATA 

Примечания:

На практике под CSV часто понимают более общий формат DSV (delimiter-separated values,
значения, разделенные разделителем), который может использовать отличные от запятой
разделители. Наиболее популярные в нашей стране разделители – символ табуляции и точка
с запятой. Причем некоторые программы, как, например, Microsoft Excel, могут исполь-
зовать тот или иной разделитель в зависимости от региональных настроек (в MS Excel –
запятая в общих настройках и точка с запятой в российских)
.

Также в качестве разделителя используются как минимум: собака, табуляция, 
вертикальная черта. Вне зависимости от использованного разделителя, остальные 
рекомендации остаются неизменными.

Дополнения W3C:

  • Имена файлов должны заканчиваться расширением .csv.
  • Файлы должны иметь кодировку UTF-8.
  • Файлы должны иметь одну строку заголовка. Эта строка должна быть первой строкой в файле.
    • Каждый столбец в файле CSV называется полем и его имя находится в строке заголовка в том же столбце .
    • Имя столбца должно быть уникальным среди полей заголовка, содержать по крайней мере один символ.
  • Строки в файле не должны содержать больше полей, чем в строке заголовка (хотя они могут содержать меньше).
  • Если CSV файл не следует этим правилам, то его специфический CSV диалект должен быть документирован согласно CSV Dialect Description Format.
 
 Запись ТЗ в CSV (по правилам 1-7)
//ПреобразоватьТЗвТекстCSV () экспортирует данные ТЗ в текст в формате CSV
//Параметры:
//ТЗ 			- Таблица значений данные которые сохраняются в файл
//флЭкспортироватьИменаКолонок - Первой строкой выводить имена колонок
//Разделитель 	- Для формата CSV разделителем является ',', но т.к. 
//				  Excel берет разделитель из региональных стандартов, то
//				  используется ';'
//
&НаСервереБезКонтекста
Функция ПреобразоватьТЗвТекстCSV(ТЗ, Разделитель = ";", флЭкспортироватьИменаКолонок = Ложь) Экспорт
		
	ТекстCSV = "";
	
	Если флЭкспортироватьИменаКолонок Тогда
		//Если нужно выгружать наименование колонок Выгружаем
		ПодготовленнаяСтрока = "";
		Для Каждого Колонка Из ТЗ.Колонки Цикл
			ПодготовленнаяСтрока = ПодготовленнаяСтрока + Колонка.Имя + Разделитель;
		КонецЦикла;
		ПодготовленнаяСтрока = Лев (ПодготовленнаяСтрока,СтрДлина(ПодготовленнаяСтрока)-1);
		
		ТекстCSV = ТекстCSV + ПодготовленнаяСтрока + Символы.ПС;
	КонецЕсли;
	
	Для Каждого Строка Из ТЗ Цикл
		ПодготовленнаяСтрока = "";
		Для Каждого Колонка Из ТЗ.Колонки Цикл
			ПреобразованноеПоле = Строка[Колонка.Имя];
			//по правилам CSV если поле содержит двойные ковычки они должны повторятся дважды
			Если Найти(ПреобразованноеПоле,"""") Тогда
				ПреобразованноеПоле = СтрЗаменить(ПреобразованноеПоле,"""","""""");
			КонецЕсли;
			//по правилам CSV если поле содержит перенос строки или запятую оно должно заключатся в двойные кавычки
			Если Найти(ПреобразованноеПоле,Разделитель) ИЛИ Найти(ПреобразованноеПоле,Символы.ПС) ИЛИ Найти(ПреобразованноеПоле,"""") Тогда
				ПреобразованноеПоле = """" + ПреобразованноеПоле + """";
			КонецЕсли;

			ПодготовленнаяСтрока = ПодготовленнаяСтрока + ПреобразованноеПоле + Разделитель;
		КонецЦикла;
		ПодготовленнаяСтрока = Лев (ПодготовленнаяСтрока,СтрДлина(ПодготовленнаяСтрока)-1);
		
		ТекстCSV = ТекстCSV + ПодготовленнаяСтрока + Символы.ПС;
	КонецЦикла;

	Возврат ТекстCSV;
КонецФункции

казалось бы - всё, но кроличья нора оказалась намного глубже!

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

		ПодготовленнаяСтрока = Лев (ПодготовленнаяСтрока,СтрДлина(ПодготовленнаяСтрока)-1);
		
		ЗаписьТекста.ЗаписатьСтроку(ПодготовленнаяСтрока);
	КонецЦикла;
	ЗаписьТекста.Закрыть();
КонецПроцедуры

метод годится для быстрой! записи _большой_ таблицы значений в файл, ведь учет кавычек и переносов в разы замедляет его... (в ответ на комментарий elinorkelt)

 
 Чтение CSV в ТЗ (конечный автомат по правилам 1,2,3,4 + 5 кавычки + 6 переносы строк)
//ПреобразоватьТекстCSVвТЗ () импортирует данные в ТЗ из текста формата CSV
//Параметры:
//ТекстCSV 		- Строка, содержащая текст в формате csv
//Разделитель 	- Для формата CSV разделителем является ',', но т.к. 
//				  Excel берет разделитель из региональных стандартов, то
//				  используется ';', поддерживает многострочные поля
//
&НаСервереБезКонтекста
Функция ПреобразоватьТекстCSVвТЗ(ТекстCSV="", Разделитель=";") Экспорт
	ТЗ = Новый ТаблицаЗначений;
	ОсобаяСтрока = "$#%^&*!xyxb$#%&*!^";	// для замены ""
	
	НомерСтроки = 1;
	Стр = СтрПолучитьСтроку(ТекстCSV,НомерСтроки);
	Пока НомерСтроки <= СтрЧислоСтрок(ТекстCSV) Цикл
		СтрокаТЗ = ТЗ.Добавить();
		НомерПоля = 0;
		Пока Стр <> "" Цикл
			Токен = "";
			ПозицияРазделителя = Найти(стр, Разделитель);
			ПозицияОткрКавычек = Найти(стр, """");
			//"";""
			Если ПозицияОткрКавычек > 1 И Сред(стр, ПозицияОткрКавычек-1, 1) <> Разделитель Тогда
				ПозицияОткрКавычек = 0;
			КонецЕсли;
			Если (ПозицияРазделителя > ПозицияОткрКавычек ИЛИ ПозицияРазделителя = 0) И ПозицияОткрКавычек > 0 Тогда
				// начинающееся с кавычек читаем до тех пор
				Токен = Сред(Стр, 1, ПозицияОткрКавычек);
				Стр = СтрЗаменить(Сред(Стр, ПозицияОткрКавычек+1), """""", ОсобаяСтрока);
				
				ПозицияЗакрКавычек = Найти(Стр, """");
				Пока ПозицияЗакрКавычек = 0 Цикл
					Токен = Токен + Стр + Символы.ПС;
					НомерСтроки = НомерСтроки + 1;
					Стр = СтрПолучитьСтроку(ТекстCSV, НомерСтроки);
					Стр = СтрЗаменить(Стр, """""", ОсобаяСтрока);
					// пока не встретим закрывающие
					ПозицияЗакрКавычек = Найти(Стр, """");
				КонецЦикла;
				ПозицияРазделителя=Найти(Сред(Стр,ПозицияЗакрКавычек), Разделитель);
				ПозицияРазделителя = ?(ПозицияРазделителя>0, ПозицияЗакрКавычек + ПозицияРазделителя-1, 0);
			КонецЕсли;

			Токен = Токен + ?(ПозицияРазделителя>0, Сред(Стр, 1, ПозицияРазделителя-1), Стр);
			Стр = ?(ПозицияРазделителя>0, Сред(Стр, ПозицияРазделителя+1), "");
			
			Если Лев(Токен, 1) = """" Тогда
				Токен = Сред(Токен, 2);
				Токен = ?(Прав(Токен, 1) = """", Сред(Токен, 1, СтрДлина(Токен)-1), Токен);
			КонецЕсли;
			Токен = ?(Токен = ОсобаяСтрока, "", Токен);
			Токен = СтрЗаменить(Токен, ОсобаяСтрока, """");
			
			НомерПоля = НомерПоля + 1;
			Если ТЗ.Колонки.Количество()<НомерПоля Тогда
				ТЗ.Колонки.Добавить("Колонка"+НомерПоля, Новый ОписаниеТипов("Строка"));
			КонецЕсли;
			СтрокаТЗ[НомерПоля-1] = Токен;

		КонецЦикла;
		НомерСтроки = НомерСтроки + 1;
		Стр = СтрПолучитьСтроку(ТекстCSV, НомерСтроки);
	КонецЦикла;
	Возврат ТЗ;
КонецФункции

ps: данный автомат по разбору abnf грамматики считаю неудачным, так как он непредсказуемо ломается при неправильных входных данных

 
 Чтение данных с помощью COM (виндовый объект ADODB.Connection поддерживает все 7 правил)
// Функция возвращает ТабличныйДокумент с данными файла.
//
Функция ПрочитатьCSV_ADO(ИмяФайла, Разделитель=",")
	ТабДок = Новый ТабличныйДокумент;
	Файл = Новый Файл(ИмяФайла);
	
	Connection=Новый COMОбъект("ADODB.Connection");
	Connection.Open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source="+Файл.Путь+";Extended Properties=""text;HDR=No;IMEX=1;FMT=Delimited""");

	RecordSet=Новый COMОбъект("ADODB.Recordset");
	RecordSet.ActiveConnection = Connection;
	
	RecordSet.Open("select * from "+Файл.Имя, Connection);
	
	сч=0;
	Пока НЕ RecordSet.EOF() Цикл
		сч=сч+1;
		
		Для й=0 по RecordSet.Fields.Count-1 Цикл
			ТабДок.Область(сч, й+1).Текст = RecordSet.Fields(й).Value;
		КонецЦикла;
		Если сч%1000=0 Тогда	// ~ 1000 в секунду
			Состояние(""+сч+" ...");
			ОбработкаПрерыванияПользователя();
		КонецЕсли;
		RecordSet.MoveNext();
	КонецЦикла;
	
	RecordSet.Close();
	Connection.Close();
	Возврат ТабДок;
КонецФункции

Для больших файлов можно использовать Microsoft.Jet.OLEDB. Понимает даты, числа и многострочные поля. Скорость: ~3000 строк в секунду. На msdn можно найти описание грамматики и Schema.ini. Пример использования здесь //infostart.ru/public/98398/

данный способ считаю наиболее приемлемым при разборе больших файлов, т.к. встреча с неправильными данными не ломает чтение последующих строк

 
 Чтение данных с помощью внешней компоненты GameWithFire.dll
// Функция возвращает ТаблицуЗначений с данными файла.
//
// Источник: http://forum.script-coding.com/viewtopic.php?id=5664
//
Функция ПрочитатьCSV_GWF(ИмяФайла)
	Файл = Новый Файл(ИмяФайла);

	// Schema.ini уже должен быть подготовлен
    objRec = Новый COMОбъект("ADODB.Recordset");
    strQuery = "SELECT * FROM [" + Файл.Имя + "]";
    strConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + Файл.Путь + ";Extended Properties=""text;HDR=No""";
    adOpenStatic = 3;
    adLockOptimistic = 3;
    adCmdText = 1;
    objRec.Open(strQuery, strConn, adOpenStatic, adLockOptimistic, adCmdText);
    
    Если ПодключитьВнешнююКомпоненту("GameWithFire.ADOUtils") Тогда
	    ADOUtils = Новый("AddIn.ADOUtils");
	    Возврат ADOUtils.ADORecordsetToValueTable(objRec);	// ~ 3000 в сек
	Иначе
		Сообщить("Не удалось подключить компоненту GameWithFire");
		Возврат Новый ТаблицаЗначений;
	КонецЕсли;
КонецФункции

 

ps: поводом для написания этой статьи стал безуспешный поиск функции чтения csv средствами платформы, поддерживающей экранированные поля с символами переноса строки

Ссылки:

1. IETFRFC 4180. Common Format and MIME Type for CSV Files
2. W3C. See sparql11-results-csv-tsv, the first W3C recommendation scoped in CSV and filling some of RFC4180's lacks
3. RFC 4180, спецификация (рус.)
4. JSON Data SpecificationsCSV Dialect Description Format (CSVDDF)

upd: для чтения больших файлов данный код совершенно не годится, лучше использовать adodb или gamewithfire,
вот сравнение времени выполнения методов для файла из 10000 строк, на слабом процессоре:

  • Native - 28 578 мс
  • ADODB - 8 336 мс
  • GWF - 7 236 мс
  • Native regexp - 14 078 мс

upd2Чтение csv файлов - чтение с использованием регулярок, которое быстрее в 2 раза чем вариант Native

Исходный код: github: https://github.com/kuzyara/ConvertCSV

Проверено на следующих конфигурациях и релизах:

  • Управление торговлей, редакция 11, релизы 11.5.18.41

ТЗ ТаблицаЗначений формат CSV импорт экспорт RFC 4180 ADO OLEDB

См. также

SALE! 20%

Перенос данных 1C Файловый обмен (TXT, XML, DBF), FTP Системный администратор Программист Платформа 1С v8.3 1С:Розница 2 1С:Управление нашей фирмой 1.6 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х 1С:Управление нашей фирмой 3.0 1С:Розница 3.0 Россия Платные (руб)

Правила в универсальном формате обмена для ERP 2.5, КА 2.5, УТ 11.5, БП 3.0, Розница, УНФ, для последних версий конфигураций. Ссылки на другие конфигурации в описании публикации. Правила совместимы со всеми другими версиями конфигураций новыми и старыми, поддерживающими обмен и синхронизацию в формате EnterpriseData. Не требуется синхронного обновления правил после обновления другой конфигурации, участвующей в обмене. Типовой обмен через планы обмена кнопкой Синхронизация вручную или автоматически по расписанию, или вручную обработкой.

26280 22338 руб.

12.06.2017    141466    798    297    

419

SALE! 10%

Перенос данных 1C Файловый обмен (TXT, XML, DBF), FTP Системный администратор Программист Платформа 1С v8.3 1С:Управление производственным предприятием 1С:Бухгалтерия 3.0 Россия Бухгалтерский учет Управленческий учет Платные (руб)

Перенос данных из 1С:Управление производственным предприятием 1.3 в 1С:Бухгалтерия предприятия 3.0 с помощью правил обмена. Переносятся остатки, документы (обороты за период), справочная информация. Правила проверены на конфигурациях УПП 1.3 (1.3.234.x) и БП 3.0 (3.0.161.x). Правила подходят для версии ПРОФ и КОРП.

35000 31500 руб.

15.12.2021    23985    169    51    

127

SALE! 10%

Перенос данных 1C Файловый обмен (TXT, XML, DBF), FTP Системный администратор Программист Платформа 1С v8.3 Оперативный учет 1С:Управление торговлей 10 Россия Управленческий учет Платные (руб)

Перенос данных из 1С:Управление торговлей 10.3 в 1С:Управление торговлей 11.5 с помощью правил обмена. Переносятся остатки, документы (обороты за период), справочная информация. Правила проверены на конфигурациях УТ 10.3 (10.3.88.x) и УТ 11.5 (11.5.19.x).

35000 31500 руб.

23.07.2020    51187    228    69    

185

SALE! 10%

Перенос данных 1C Файловый обмен (TXT, XML, DBF), FTP Программист Платформа 1С v8.3 1С:ERP Управление предприятием 2 1С:Комплексная автоматизация 2.х 1С:Зарплата и Управление Персоналом 3.x Россия Бухгалтерский учет Управленческий учет Платные (руб)

Перенос данных из ERP в ЗУП 3 | из КА 2 в ЗУП | Готовые правила конвертации данных (КД 2) для переноса остатков, документов с движениями и справочной информации 3 | Есть перенос начальной задолженности по зарплате и начальной штатной расстановки на выбранную дату | Обороты за прошлые годы (данные для расчета среднего) переносятся свернуто в документ "Перенос данных" | Есть фильтр по организациям | Документы за текущий период переносятся сразу с движениями, поэтому не потребуется делать перерасчеты | Перенос можно проверить перед покупкой, обращайтесь!

53111 47800 руб.

03.12.2020    36568    94    66    

89

SALE! 10%

Перенос данных 1C Файловый обмен (TXT, XML, DBF), FTP Системный администратор Программист Платформа 1С v8.3 1С:Комплексная автоматизация 1.х 1С:Управление производственным предприятием 1С:Бухгалтерия 3.0 Россия Бухгалтерский учет Платные (руб)

Перенос данных из 1С:Управление производственным предприятием 1.3 в 1С:Бухгалтерия предприятия 3.0 с помощью правил обмена | Можно выполнить переход с УПП на БП 3 или запускать выгрузку данных за выбранный период времени | Переносятся документы, начальные остатки и вся справочная информация | Есть фильтр по организации и множество других параметров выгрузки | Поддерживается несколько сценариев работы: как первичный полный перенос, так и перенос только новых документов | Перенос данных возможен в "1С: Бухгалтерия 3.0" версии ПРОФ, КОРП или базовую | Переход с "1С: УПП1.3" / "1С:КА 1.1" на "1С:БП3.0" с помощью правил конвертации будет максимально комфортным! | Можно бесплатно проверить перенос на вашем сервере!

48278 43450 руб.

25.02.2015    171155    303    257    

378

SALE! 15%

Перенос данных 1C Файловый обмен (TXT, XML, DBF), FTP Системный администратор Программист Платформа 1С v8.3 Платформа 1C v8.2 1С:Комплексная автоматизация 1.х 1С:Управление торговлей 10 1С:Управление производственным предприятием Россия Платные (руб)

Регулярный обмен, выгрузка, перенос из КА 1.1, УПП 1.3, УТ 10.3 для обмена с любыми конфигурациями, поддерживающими обмен в формате EnterpriseData (КД3) - БП 3.0, ERP, КА 2, УТ 11, Розница 2, УНФ 1.6 и другими. Правила для старых и доработанных конфигураций не требуют синхронного обновления и совместимы с новыми и будущими конфигурациями. Обмен по расписанию, через папку, FTP, почту.

15300 13005 руб.

18.02.2016    186855    589    509    

526

SALE! 10%

Перенос данных 1C Взаиморасчеты Оптовая торговля Логистика, склад и ТМЦ Файловый обмен (TXT, XML, DBF), FTP Системный администратор Программист Платформа 1С v8.3 1С:Управление торговлей 10 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Россия Управленческий учет Платные (руб)

Можно проверить до покупки, оставьте заявку! Воспользовались более 268 компаний! Перенос данных из УТ 10.3 в УТ 11 | из УТ 10.3 в КА 2 | из УТ 10.3 в ERP. Предлагаем качественное и проверенное временем решение для перехода с УТ 10.3. Можно перенести начальные остатки, нормативно-справочную информацию и все возможные документы. При выгрузке можно установить отбор по периоду, организациям и складам. При выходе новых релизов конфигураций 1C оперативно выпускаем обновление переноса данных.

55778 50200 руб.

24.04.2015    194950    150    243    

280

SALE! 10%

Перенос данных 1C Файловый обмен (TXT, XML, DBF), FTP Системный администратор Программист Платформа 1С v8.3 1С:Комплексная автоматизация 1.х 1С:Управление торговлей 10 1С:Управление производственным предприятием 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Россия Платные (руб)

Перенос данных из ERP в УПП 1.3 | из КА 2 в КА 1.1 | из КА 2 в УПП 1.3 | из КА 2 в УТ 10.3 | из ERP в КА 1.1 | из ERP в УТ 10.3 | из УТ 11 в УТ 10.3 | из УТ 11 в УПП 1.3 | из УТ 11 в КА 1.1 | Можно переносить только новые объекты, найденные в приемнике перезаписываться не будут | Есть фильтр по организации при выгрузке данных | Оперативно обновляем на новые релизы 1С

53111 47800 руб.

28.11.2015    83235    32    125    

64
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. rise 05.04.17 17:50 Сейчас в теме
А вот такая строка неверно читается
aaa,"","ccc"

Получается
aaa,", ccc
2. пользователь 10.04.17 04:54
Сообщение было скрыто модератором.
...
4. kuzyara 2090 11.06.19 05:08 Сейчас в теме
(1)
aaa,"","ccc"

ну почему же, читается
разделитель не выставили?
Прикрепленные файлы:
ikalmykia; +1 Ответить
6. ikalmykia 28.01.20 12:56 Сейчас в теме
3. пользователь 08.11.17 15:33
Сообщение было скрыто модератором.
...
5. Yimaida 38 05.12.19 01:23 Сейчас в теме
(6) Спасибо за функции и обработку. Отлично загружает через ПреобразоватьТЗвТекстCSV() многострочные элементы.
ikalmykia; +1 Ответить
7. elinorkelt 12.03.21 12:26 Сейчас в теме
Ошибка при загрузке строк с Символы.ПС из ТЗ в csv. Сбиваются строки, текст переносится, а не попадает в одну ячейку.
В процедуре ПреобразоватьТЗвТекстCSV должно быть так

Для Каждого Строка Из ТЗ Цикл
		ПодготовленнаяСтрока = "";
		Для Каждого Колонка Из ТЗ.Колонки Цикл
			ПреобразованноеПоле = Строка[Колонка.Имя];
			//по правилам CSV если поле содержит перенос строки или запятую оно должно заключатся в двойные кавычки
			Если Найти(ПреобразованноеПоле,Разделитель) ИЛИ Найти(ПреобразованноеПоле,Символы.ПС) Тогда 
				//ИЛИ Найти(ПреобразованноеПоле,"""") Тогда
				ПреобразованноеПоле = """" + ПреобразованноеПоле + """";
			КонецЕсли;
			//по правилам CSV если поле содержит двойные кавычки они должны повторятся дважды
			Если Найти(ПреобразованноеПоле,"""") Тогда
				ПреобразованноеПоле = СтрЗаменить(ПреобразованноеПоле,"""","""""");
			КонецЕсли;
			
			ПодготовленнаяСтрока = ПодготовленнаяСтрока + """" + ПреобразованноеПоле + """"+ Разделитель;
		КонецЦикла;
		ПодготовленнаяСтрока = Лев (ПодготовленнаяСтрока,СтрДлина(ПодготовленнаяСтрока)-1);
		
		ЗаписьТекста.ЗаписатьСтроку(ПодготовленнаяСтрока);
	КонецЦикла;
Показать
simgo83; kuzyara; +2 Ответить
8. avalakh 571 28.12.21 09:50 Сейчас в теме
99% работает, но наткнулся на такое значение ячейки (см. скрин), не прочитало. Openoffice такое видит. Файл тоже прикрепил, если вдруг понадобится
Прикрепленные файлы:
rules.zip
14. kuzyara 2090 10.02.23 08:12 Сейчас в теме
(8) читает

обновил обработку
Прикрепленные файлы:
9. Lichi001 80 28.12.21 12:36 Сейчас в теме
Отлично работает, автору БОЛЬШОЕ спасибо. Весь интернет перерыл ни чего толкового не нашел кроме этого!!!
10. KAV2 157 23.08.22 21:48 Сейчас в теме
Функция ПреобразоватьТекстCSVвТЗ на мой взгляд удовлетворяет всем 7-ми требованиям стандарта, но с ней есть некоторые проблемы, во первых, в ней может происходить зацикливание при поиске закрывающей кавычки, во вторых, используется некоторая ОсобаяСтрока для замены двойных кавычек, а вероятность появления подобной строки в CSV файле хоть и низкая но и не нулевая.
Предлагаю вашему вниманию несколько доработанную версию этой функции. Она напрямую читает CSV файл, поскольку тесты показали, что по крайней мере на SSD накопителе, прямое потоковое построчное чтение работает быстрее чем через промежуточный буффер:

Функция ПрочитатьCSVФайлВТаблицу(ИмяФайла, Разделитель=";", КоличествоПервыхСтрокПропустить = 0, КоличествоКолонок = Неопределено)
        
    ЧтениеТекста = Новый ЧтениеТекста(ИмяФайла, КодировкаТекста.UTF8 ,,,Ложь);
    
    ТЗ = Новый ТаблицаЗначений;
    Колонки = ТЗ.Колонки;
    ОписаниеТиповСтрока = Новый ОписаниеТипов("Строка");
    
    Если КоличествоКолонок <> Неопределено Тогда
        Для НомерКолоки = 1 По КоличествоКолонок Цикл
            Колонки.Добавить("Колонка"+НомерКолоки, ОписаниеТиповСтрока);
        КонецЦикла;
    КонецЕсли;
    
    НомерСтроки = 1;
    Стр = ЧтениеТекста.ПрочитатьСтроку();
    Пока Стр <> Неопределено Цикл
        Если НомерСтроки < 1 + КоличествоПервыхСтрокПропустить Тогда
            Стр = ЧтениеТекста.ПрочитатьСтроку();
            НомерСтроки = НомерСтроки + 1;
            Продолжить;
        КонецЕсли;
        СтрокаТЗ = ТЗ.Добавить();
        НомерПоля = 0;
        Пока Стр <> "" Цикл
            Токен = "";
            ПозицияРазделителя = Найти(стр, Разделитель);
            ПозицияОткрКавычек = Найти(стр, """");
            //"";""
            Если ПозицияОткрКавычек > 1 И Сред(стр, ПозицияОткрКавычек-1, 1) <> Разделитель Тогда
                ПозицияОткрКавычек = 0;
            КонецЕсли;
            Если (ПозицияРазделителя > ПозицияОткрКавычек ИЛИ ПозицияРазделителя = 0) И ПозицияОткрКавычек > 0 Тогда
                // начинающееся с кавычек читаем до тех пор
                Токен = Лев(Стр, ПозицияОткрКавычек);
                Стр = Сред(Стр, ПозицияОткрКавычек+1);
                ПозицияДляПоискаЗакрКавычек = 1;
                ПозицияЗакрКавычек = 0;
                Пока ПозицияЗакрКавычек = 0 Цикл
                    Если СтрДлина(Стр) >= ПозицияДляПоискаЗакрКавычек Тогда
                    ПозицияЗакрКавычек = СтрНайти(Стр, """",,ПозицияДляПоискаЗакрКавычек);
                    КонецЕсли;
                    
                    Если ПозицияЗакрКавычек > 0 И Сред(Стр,ПозицияЗакрКавычек + 1, 1) = """" Тогда
                        ПозицияДляПоискаЗакрКавычек = ПозицияЗакрКавычек + 2;
                        ПозицияЗакрКавычек = 0;
                        Продолжить; //это просто экранированная кавычка, а не кавычка закрывающее поле
                    ИначеЕсли ПозицияЗакрКавычек > 0 Тогда
                        Прервать;
                    Иначе
                        Токен = Токен + Стр + Символы.ПС;
                        НомерСтроки = НомерСтроки + 1;
                        Стр = ЧтениеТекста.ПрочитатьСтроку();
                        Если Стр = Неопределено Тогда
                            Стр = "";
                            Прервать; // файл закончился, закрывающую кавычку не нашли
                        КонецЕсли;         
                        ПозицияДляПоискаЗакрКавычек = 1; // ищем с начала новой, полученной строки
                    КонецЕсли;
                                        
                КонецЦикла;
                
                Если СтрДлина(Стр) > ПозицияЗакрКавычек Тогда
                    ПозицияРазделителя=СтрНайти(Стр, Разделитель,,ПозицияЗакрКавычек + 1);
                Иначе
                    ПозицияРазделителя = 0;
                КонецЕсли;
            КонецЕсли;
            
            Если ПозицияРазделителя>0 Тогда
                Токен = Токен + Лев(Стр, ПозицияРазделителя-1);
                Стр = Сред(Стр, ПозицияРазделителя+1);
            Иначе
                Токен = Токен + Стр; // разделитель не нашли, добавляем оставшуюся часть строки
                Стр = ""; // строка полностью обработана
            КонецЕсли;
            
            // Уберем экранирующие кавычки у поля, если они там были
            Если Лев(Токен, 1) = """" Тогда
                Токен = Сред(Токен, 2);
                Токен = ?(Прав(Токен, 1) = """", Лев(Токен, СтрДлина(Токен)-1), Токен);
            КонецЕсли;
                        
            // убираем двойные кавычки
            Токен = СтрЗаменить(Токен, """""", """");
            
            НомерПоля = НомерПоля + 1;
            Если КоличествоКолонок = Неопределено Тогда
                Если Колонки.Количество()<НомерПоля Тогда
                    Колонки.Добавить("Колонка"+НомерПоля, ОписаниеТиповСтрока);
                КонецЕсли;
            ИначеЕсли НомерПоля > КоличествоКолонок Тогда
                Прервать;
            КонецЕсли;
            СтрокаТЗ[НомерПоля-1] = Токен;
            
        КонецЦикла;
        НомерСтроки = НомерСтроки + 1;
        Стр = ЧтениеТекста.ПрочитатьСтроку();
    КонецЦикла;
    
    ЧтениеТекста.Закрыть();
    
    Возврат ТЗ;
КонецФункции

Показать
12. KAV2 157 15.09.22 10:50 Сейчас в теме
(10) В этой версии есть ошибка, не учитывается параметр КоличествоПервыхСтрокПропустить. Поскольку здесь нельзя редактировать комментарии, выложу актуальную версию на гитхабе (чтобы не дублировать код):
ПрочитатьCSVФайлВТаблицу.bsl
13. KAV2 157 15.11.22 05:00 Сейчас в теме
(12) Добавлю также функцию для чтения CSV в массив соответствий на тонком клиенте:
ПрочитатьCSVНаКлиенте.bsl
11. Arxxximed 37 12.09.22 17:01 Сейчас в теме
Господа, по моему городить такие большие процедуры для чтения многострочных полей CSV слишком муторно и не понятно.
Может достаточно считать четность кавычек?

Вот мое решение: CSV. Чтение многострочных полей с экранированными символами

Спасибо автору за правила. Они натолкнули меня на эту мысль
Оставьте свое сообщение