Книга знаний

1С:Предприятие / Приемы программирования / Внешние обработки

Преобразование csv в таблицу значений

А то достали уже с этим вопросом.Автор статьи: Fragster | Редакторы: Живой Ископаемый, Kreont, kuzyara
Последняя редакция №16 от 22.08.16 | История
URL: http://kb.mista.ru/article.php?id=711

Ключевые слова: csv, dsv, преобразовать, открыть


На выходе - в Список - список колонок, Таблица - таблица с данными.


Функция СтрокаВСписок(Стр,Разделитель = ";")
    Список = СоздатьОбъект("СписокЗначений");
    Б = СтрДлина(Разделитель)-1;
    Пока СтрДлина(Стр)>0 Цикл
        А = Найти(Стр,Разделитель);
        Если А>0 Тогда
            ВрСтр = СокрЛП(Лев(Стр,А-1));
            Стр = СокрЛП(Прав(Стр,СтрДлина(Стр)-А-Б));
        Иначе
            // последняя
            ВрСтр = СокрЛП(Стр);
            Стр = "";
        КонецЕсли;

        Если (Лев(ВрСтр,1) = """") И (Прав(ВрСтр,1) = """") Тогда
            ВрСтр = Сред(ВрСтр,2,СтрДлина(ВрСтр)-2);
        КонецЕсли;

        Список.ДобавитьЗначение(ВрСтр);
    КонецЦикла;

    Возврат(Список)
КонецФункции

Процедура Парсер(ИмяФайла, Список, Таблица);
    Текст = СоздатьОбъект("Текст");
    Сообщить(ИмяФайла);
    Текст.Открыть(ИмяФайла);
    Если Текст.КоличествоСтрок()=0 Тогда
        Возврат;
    КонецЕсли;
    Заголовки = СокрЛП(Текст.ПолучитьСтроку(1));
    Список = СоздатьОбъект("СписокЗначений");
    Список = СтрокаВСписок(Заголовки);

    Таблица = СоздатьОбъект("ТаблицаЗначений");
    Для Сч = 1 По Список.РазмерСписка() Цикл
        Таблица.НоваяКолонка(Список.ПолучитьЗначение(Сч));
    КонецЦикла;

    Для Сч = 2 По Текст.КоличествоСтрок() Цикл
        Список1 = СтрокаВСписок(Текст.ПолучитьСтроку(Сч));
        Если СокрЛП(Текст.ПолучитьСтроку(Сч))="" Тогда
            Продолжить;
        КонецЕсли;
        Таблица.НоваяСтрока();
        Для Сч1 = 1 По Список1.РазмерСписка() Цикл
            Таблица.УстановитьЗначение(Сч-1,Сч1,Список1.ПолучитьЗначение(Сч1));
        КонецЦикла;
    КонецЦикла;

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



Заляпуха, конечно, но работает в простейших случаях


Также можно сделать через ADO:
    Файл = Новый Файл(ИмяФайла);
    Если Не Файл.Существует() Тогда
        Предупреждение("Файл не существует!");
        Возврат;
    КонецЕсли;

    Connection    = Новый ComОбъект("ADODB.Connection");
    Command        = Новый ComОбъект("ADODB.Command");
    СтрокаПодключения = "Driver={Microsoft Text Driver (*.txt; *.csv)};Dbq="+Файл.Путь
+";Extensions=csv;";
    Connection.ConnectionString = СтрокаПодключения;
    Connection.Open();
    Command.ActiveConnection = Connection;
    
    Команда = "SELECT * FROM ["+файл.Имя+"]";
    Command.CommandText = Команда;
    Recordset = Command.Execute();
    Сообщить("Выполнил");
    
    ЧислоПолей = Recordset.Fields.Count;

   и т.д.

==========

Дополнение:
функция, которая правильно раскладывает строки типа вида:
20100912; 17.19;"Назначение платежа; которое не нужно делить на подстроки"
То есть на три подстроки а не четыре:


   
RegExp = Новый COMОбъект("VBScript.RegExp");
    Результат = Новый Массив();
    
    RegExp.IgnoreCase = Ложь; //Игнорировать регистр 
    RegExp.Global = Истина; //Поиск всех вхождений шаблона 
    RegExp.MultiLine = Ложь; //Многострочный режим 
    
    RegExp.Pattern = "(?:^|;)(\""(?:[^\""]+|\""\"")*\""|[^;]*)"; //вот наш супер шаблон 
    //RegExp.Pattern = ";|;|;|;|;;|;|;|;|;|;|;|;|;;|;|;"; //вот наш супер шаблон 
    Matches=RegExp.Execute(Стр);
    ЧислоВхождений=Matches.Count();
    //Сообщить(Стр,СтатусСообщения.Важное);
    Если ЧислоВхождений>0 Тогда 
        Для к = 0 По ЧислоВхождений-1 Цикл
            Match = Matches.Item(к);
            
            SubMatches = Match.SubMatches;
            ЧислоПодвыражений=SubMatches.Count();
            Для н = 0 По ЧислоПодвыражений-1 Цикл
                SubMatch=SubMatches.Item(н);
                Если SubMatch="" Тогда
                    //Продолжить;
                КонецЕсли;    
                Результат.Добавить(SubMatch);
                //Сообщить("Подстрока: "+SubMatch);
            КонецЦикла;    
        КонецЦикла;
    Иначе
        //Сообщить("Вхождений шаблона не найдено");
    КонецЕсли;
    Возврат Результат;


Пример:
http://screencast.com/t/WeZtHFKzhsob



Парсинг строки сделан рекурсивно, допускается любое вложение разделителей:
20100912; 17.19;"Назначение платежа; ""фирма ""ООО"" ;АТ; "" которое не нужно делить на
подстроки"


// На вход: Строка формата csv
// На выходе: массив значений
Функция ПарсингСтрокиВМассив(Знач СтрокаВходящая,РазделительПолей = ",",РазделительТекста = 
"""")
    МассивРезультат = Новый Массив;
    СтрокаНаПарсинг = СтрокаВходящая;
    Если Прав(СтрокаНаПарсинг,1) <> РазделительПолей Тогда
        СтрокаНаПарсинг = СтрокаНаПарсинг + РазделительПолей;
    КонецЕсли;
    инд = СтрДлина(СтрокаНаПарсинг);
    Пока инд > 1 Цикл
        Кусок = ПолучитьСтроку(СтрокаНаПарсинг,РазделительПолей,РазделительТекста);
        
МассивРезультат.Добавить(ОчисткаСтроки(Кусок,РазделительПолей,РазделительТекста));
        СтрокаНаПарсинг  = Сред(СтрокаНаПарсинг,СтрДлина(Кусок)+1);
        инд = СтрДлина(СтрокаНаПарсинг);
    КонецЦикла;
    Возврат МассивРезультат;
КонецФункции

// На вход: тип "ТекстовыйДокумент"
// На выходе: таблица значений
Функция ПарсингВТаблицуЗначений(Знач Текст,РазделительПолей = ",",РазделительТекста = """")
    ТЗ = Новый ТаблицаЗначений; 
    КвоСтрок = Текст.КоличествоСтрок();
    Для инд_строк = 1 По КвоСтрок Цикл
        СтрокаНаПарсинг = Текст.ПолучитьСтроку(инд_строк);
        Если Прав(СтрокаНаПарсинг,1) <> РазделительПолей Тогда
            СтрокаНаПарсинг = СтрокаНаПарсинг + РазделительПолей;
        КонецЕсли;
        СтрокаТЗ = ТЗ.Добавить();
        ТЗКолонка = -1;
        и_перебор = СтрДлина(СтрокаНаПарсинг);
        Пока и_перебор > 1 Цикл
            ТЗКолонка = ТЗКолонка + 1;
            Если инд_строк = 1 Тогда
                ТЗ.Колонки.Добавить();
            КонецЕсли;    
            Кусок = 
ПолучитьСтроку(СтрокаНаПарсинг,РазделительПолей,РазделительТекста);
            СтрокаТЗ[ТЗКолонка] = 
ОчисткаСтроки(Кусок,РазделительПолей,РазделительТекста);
            СтрокаНаПарсинг  = Сред(СтрокаНаПарсинг,СтрДлина(Кусок)+1);
            и_перебор = СтрДлина(СтрокаНаПарсинг);
        КонецЦикла;
    КонецЦикла;    
    Возврат ТЗ;
КонецФункции

Функция ПолучитьСтроку(СтрокаВходная,РазделительПолей = ",",РазделительТекста = """")
    Результат = "";
    инд = 1;
    Пока инд < СтрДлина(СтрокаВходная) Цикл
        Если Сред(СтрокаВходная,инд,1) = РазделительПолей Тогда
            Результат = Результат + РазделительПолей;
            Прервать;
        ИначеЕсли Сред(СтрокаВходная,инд,1) = РазделительТекста Тогда
            ЧастковийРезультат = Сред(СтрокаВходная,инд,1) + 
ПолучитьСтроку(Сред(СтрокаВходная,инд+1),РазделительТекста,РазделительТекста);
            Результат = Результат + ЧастковийРезультат;
            инд = инд + СтрДлина(ЧастковийРезультат);
        Иначе
            Результат = Результат + Сред(СтрокаВходная,инд,1);
            инд = инд + 1;
        КонецЕсли;
    КонецЦикла;    
    Возврат Результат;
КонецФункции

Функция ОчисткаСтроки(Знач СтрокаВходная,РазделительПолей = ",",РазделительТекста = """")
    Если Прав(СтрокаВходная,1) = РазделительПолей Тогда
        СтрокаВходная = Сред(СтрокаВходная,1,СтрДлина(СтрокаВходная)-1);
    КонецЕсли;
    Если Сред(СтрокаВходная,0,1) = РазделительТекста Тогда 
        СтрокаВходная = Сред(СтрокаВходная,2,СтрДлина(СтрокаВходная)-2);
        СтрокаВходная = СтрЗаменить(СтрокаВходная,РазделительТекста
+РазделительТекста,РазделительТекста);
    КонецЕсли;
    Возврат СтрокаВходная;
КонецФункции


// Пример импорта из CSV файла в Таблицу Значений
    TXTФайл = Новый ТекстовыйДокумент;
       TXTФайл.Прочитать(ФайлCSV); 
    ТЗТест = ПарсингВТаблицуЗначений(TXTФайл,",","""");
    Если ТЗТест.Количество() > 0 Тогда
        ТЗТест.ВыбратьСтроку();
    КонецЕсли;    
    

//  Пример импорта каждой строки CSV-формата в массив значений
    TXTФайл = Новый ТекстовыйДокумент;
    TXTФайл.Прочитать(ФайлCSV); 
    КвоСтрок = TXTФайл.КоличествоСтрок();
    Для инд = 1 По КвоСтрок Цикл
        очереднаяСтрока = TXTФайл.ПолучитьСтроку(инд);
        МасивТест = ПарсингСтрокиВМассив(очереднаяСтрока,",","""");    
        Сообщить("--------------< " + инд + " >---------------");
        Для Каждого инд_масс из МасивТест Цикл
            Сообщить(инд_масс);
        КонецЦикла;    
    КонецЦикла;



Обработка для теста импорта CSV-файлов:
http://commerce.at.ua/load/0-0-0-3-20

==========

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

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

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

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

Обработка для теста:
http://infostart.ru/public/541555/

Описание | Рубрикатор | Поиск | ТелепатБот | Захваченные статьи | Установки | Форум
© Станислав Митичкин (Волшебник), 2005-2024 | Mista.ru

Яндекс.Метрика