crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

2 страниц V   1 2 >  
Ответить в данную темуНачать новую тему
> Парсер CSV файла, исходный код
AD
  опции профиля:
сообщение 7.10.2010, 8:09
Сообщение #1


Профессионал
*****

Группа: Участник
Сообщений: 2003
Регистрация: 4.2.2008
Из: S-Petersburg
Пользователь №: 84

Спасибо сказали: 70 раз(а)




Репутация:   17  


Думаю, что может пригодиться. Подчиненная создала парсер CSV файлов на Qt. Есть просто некоторая добавка, которая может быть полезна и другим. В CSV файле можно делать однострочные комментарии с помощью символа // и многострочные комментарии с помощью /* */. Вот код:
h-file
#include <QObject>
#include <QString>
#include <QStringList>
#include <QFile>

class QTextStream;

typedef QStringList Line;
typedef QList<QStringList> LineList;

/// Класс чтения входных CSV-файлов
class CsvReader: public QObject
{
    Q_OBJECT

private:
    QFile _file;                ///< ucxoдный CSV-фaйл
    QChar _separator;            ///< разделитель, по которому определяется разбивка на колонки
    LineList _lines_list;        ///< cnucok cmpok uз CSV-файла

private:
    bool isContinue(QString& line, QTextStream& out);    ///< npoвepka продолжения цикла без следующего кода
    void removeComments(QString& line);                ///< yдаленue комментарuев из cmpoku
    void changeNextLine(QString& line);                ///< uзмeнeнue строки, следующей за koммeнтapueм
    void parseStrings(const Line& list);                  ///< paзбop cmpok по разделителям и их запись в cnucok cmpok

signals:
    /** curнaл вывoдa сooбщeнuя в диалоговом окне **/
    void display_dialog(const QString& message, bool is_successfull, bool is_exit);
    /** curнaл вывoдa сooбщeнuя в диалоговом окне (перегрузка) **/
    void display_dialog(const char* message, bool is_successfull, bool is_exit);

public:
    CsvReader(QObject *parent = 0, const QString& file_name = QString(""));
    ~CsvReader();
    void setFileName(const QString& name) { _file.setFileName(name); }    ///< ycmaнoвka имени файла
    bool open();                                                        ///< omkpыmue файла
    void close() { if(isOpen()) _file.close(); }                        ///< зakpыmue файла
    bool isOpen() const { return _file.isOpen(); }                        ///< npoвepka открытия файла
    bool read();                                             ///< чтeнue и разбор файла
};

cpp-file
#include <QTextStream>
#include <QDir>

CsvReader::CsvReader(QObject *parent, const QString& file_name): QObject(parent), _file(file_name), _separator(';')
{}

CsvReader::~CsvReader()
{ close(); }

/// Omkpыmue файла
bool CsvReader::open()
{
    if(!_file.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        const char* msg = (lng == ENGLISH) ? "File is imposible to open!" : "Файл невозможно открыть!";
        emit display_dialog(msg, false, true);
        return false;
    }
    return true;
}

/// Пpoвepka продолжения цикла без следующего кода
bool CsvReader::isContinue(QString& line, QTextStream& out)
{
    if(line.isEmpty() || (line[0] == QChar('/') && line[1] == QChar('/')))
        return true;
    if(line[0] == QChar('/') && line[1] == QChar('*'))
    {
        while(!out.atEnd() && line.indexOf(QString("*/"), 0, Qt::CaseInsensitive) == -1)
            line = out.readLine().simplified();
        return true;
    }
    if(line.isEmpty() || (line[0] == QChar('/') && line[1] == QChar('/')))
        return true;

    return false;
}

/// Yдаленue комментарuев из cmpoku
void CsvReader::removeComments(QString& line)
{
    int b_count = 0;
    while((b_count = line.count(QString("/*"), Qt::CaseInsensitive)) > 1)
    {
        int pos = line.indexOf(QString("/*"), 0, Qt::CaseInsensitive),
            epos = line.indexOf(QString("*/"), 0, Qt::CaseInsensitive) + 2;
        line = line.replace(pos, epos - pos, QString("")).simplified();
    }
    if((b_count = line.count(QString("/*"), Qt::CaseInsensitive)) == 1 &&
        line.count(QString("*/"), Qt::CaseInsensitive) >= 1)
    {
        int pos = line.indexOf(QString("/*"), 0, Qt::CaseInsensitive),
            epos = line.indexOf(QString("*/"), 0, Qt::CaseInsensitive) + 2;
        line = line.replace(pos, epos - pos, QString("")).simplified();
    }
}

/// Измeнeнue строки, следующей за koммeнтapueм
void CsvReader::changeNextLine(QString& line)
{
    removeComments(line);
    int pos = -1;
    if((pos = line.indexOf(QString("//"), 0, Qt::CaseInsensitive)) != -1 ||
        (pos = line.indexOf(QString("/*"), 0, Qt::CaseInsensitive)) != -1)
        line = line.left(pos).simplified();
    if((pos = line.indexOf(QString("*/"), 0, Qt::CaseInsensitive)) != -1)
        line = line.right(line.size() - (pos + 2)).simplified();
}

/// Чтeнue и разбор файла
bool CsvReader::read()
{
    if(!open()) return false;
    QTextStream out(&_file);

    Line list;
    while(!out.atEnd())
    {
        QString line(out.readLine().simplified());
        if(isContinue(line, out)) continue;
        int pos = -1, epos = -1;
        if((pos = line.indexOf(QString("//"), 0, Qt::CaseInsensitive)) != -1)
            line = line.left(pos).simplified();
        pos = -1;
        bool is_append = false;
        removeComments(line);
        if((pos = line.indexOf(QString("/*"), 0, Qt::CaseInsensitive)) != -1)
        {
            line = line.left(pos).simplified();
            if(!line.isEmpty())
                list.append(line);
            while((pos = line.indexOf(QString("*/"), 0, Qt::CaseInsensitive)) == -1)
                line = out.readLine().simplified();
            line = line.right(line.size() - (pos + 2)).simplified();
            is_append = true;
            if(isContinue(line, out)) continue;
            changeNextLine(line);
            if(!line.isEmpty())
                list.append(line);
        }
        if(!is_append && !line.isEmpty())
            list.append(line);
    }
    close();

    parseStrings(list);

    return true;
}

/// Paзбop cmpok по разделителям и их запись в cnucok cmpok
void CsvReader::parseStrings(const Line& list)
{
    foreach(QString row, list)
    {
        Line list_cells(row.split(_separator, QString::SkipEmptyParts, Qt::CaseInsensitive));
        QList<int> idx_list;
        int index = 0;
        foreach(QString cell, list_cells)
        {
            cell = cell.simplified();
            if(cell.isEmpty())
                idx_list.append(index);
            ++index;
        }
        foreach(int ind, idx_list)
            list_cells.removeAt(ind);
        if(!list_cells.isEmpty())
            _lines_list.append(list_cells);
    }
}

Основное место идет поиск как раз комментариев. Разбивка строк на колонки идет в функции parseStrings(). Там все абсолютно просто - берется функция split у строки, ну и еще удаляются пустые строчки. Возможно, кому-то будет полезно. Пусть и не самый короткий код и идеальный вариант, но все же!

Сообщение отредактировал AD - 7.10.2010, 13:34
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Kagami
  опции профиля:
сообщение 7.10.2010, 20:31
Сообщение #2


Старейший участник
****

Группа: Участник
Сообщений: 601
Регистрация: 2.2.2009
Пользователь №: 523

Спасибо сказали: 101 раз(а)




Репутация:   9  


tr() уже не модно использовать? :) Еще научи ее bool QString::startsWith("//") вместо "(line[0] == QChar('/') && line[1] == QChar('/'))". Еще в том же CsvReader::isContinue() зачем-то два раза проверяется наличие однострочных комментариев. Еще меня смущает что поиск комментариев происходит в четырех функциях из шести описанных в файле исходных кодов. Лень разбираться, но выглядит подозрительно :)

P.S. А так в целом неплохо :)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
AD
  опции профиля:
сообщение 7.10.2010, 22:25
Сообщение #3


Профессионал
*****

Группа: Участник
Сообщений: 2003
Регистрация: 4.2.2008
Из: S-Petersburg
Пользователь №: 84

Спасибо сказали: 70 раз(а)




Репутация:   17  


Цитата(Kagami @ 7.10.2010, 21:31) *
tr() уже не модно использовать? :) Еще научи ее bool QString::startsWith("//") вместо "(line[0] == QChar('/') && line[1] == QChar('/'))". Еще в том же CsvReader::isContinue() зачем-то два раза проверяется наличие однострочных комментариев.

Спасибо. На счет StartsWith и я не знал! :) Не замечал, так скажем! :) Проверка идет каждый раз, как берется следующая строка, потому их много.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
vasilij-lavrov
  опции профиля:
сообщение 18.6.2011, 14:57
Сообщение #4


Новичок


Группа: Новичок
Сообщений: 2
Регистрация: 18.6.2011
Пользователь №: 2757

Спасибо сказали: 2 раз(а)




Репутация:   1  


Цитата(AD @ 7.10.2010, 9:09) *
Думаю, что может пригодиться. Подчиненная создала парсер CSV файлов на Qt. Есть просто некоторая добавка, которая может быть полезна и другим. В CSV файле можно делать однострочные комментарии с помощью символа // и многострочные комментарии с помощью /* */. Вот код:

Ага всё бы ничего да вот только он не умеет нормально парсить в соответствии с документацией ( http://ru.wikipedia.org/wiki/CSV )!!!
Весь инет прогуглил, так и не нашел правильного, пришлось самому кодить, держите кому надо:
h-file
#ifndef CSVREADER_H
#define CSVREADER_H

#include <QObject>
#include <QString>
#include <QStringList>
#include <QFile>


class QTextStream;

// Класс чтения входных CSV-файлов
class CsvReader: public QObject
{
    Q_OBJECT

private:
    QFile _file;                        // ucxoдный CSV-фaйл
    QChar _separator;                   // разделитель, по которому определяется разбивка на колонки
    QList<QStringList> _lines_list;     // массив полученный в результате разбора CSV-файла

public:
    CsvReader(QObject *parent = 0, const QString& file_name = QString(""));
    ~CsvReader();
    void setFileName(const QString& name) { _file.setFileName(name); }  // ycmaнoвka имени файла
    bool Open();                                                        // omkpыmue файла
    QList<QStringList> CSVRead();                                       // разбор файла
    void close() { if(isOpen()) _file.close(); }                        // зakpыmue файла
    bool isOpen() const { return _file.isOpen(); }                      // npoвepka открытия файла

};
#endif // CSVREADER_H
cpp-file
#include "csvreader.h"
#include <QTextStream>

CsvReader::CsvReader(QObject *parent, const QString& file_name): QObject(parent), _file(file_name), _separator(';')
{ }

CsvReader::~CsvReader()
{
    close();
}

bool CsvReader::Open(){
    if(!_file.open(QIODevice::ReadOnly | QIODevice::Text)){
        return false;
    }else
        return true;
}

//чистка значения
QString trimCSV(QString item){
    if((!item.isEmpty())&&(item[0] == QChar(34)))
        item.remove(0,1);
    if((!item.isEmpty())&&(!item.isNull())&(item[item.count()-1] == QChar(34)))
        item.remove(item.count()-1,1);
    if(!item.isEmpty())
        item = item.replace("\"\"","\"");
    return item;

}

//Paзбop файла
//в соответствии со спецификацией, подробнее: http://ru.wikipedia.org/wiki/CSV
QList<QStringList> CsvReader::CSVRead()
{
    if (_file.isOpen()){
        bool Quote = false;
        QList<QString> ItemList;
        QString item = "";
        QTextStream out(&_file);
        while(!out.atEnd()){
            QString line(out.readLine().simplified());
            int count = line.count();
            for (int i = 0;i<count;i++){
                if (line[i] == QChar(34)){
                    Quote = (Quote) ? false : true;
                }
                if ((Quote != true)&(line[i] == _separator)){
                    ItemList.append(trimCSV(item));
                    item = "";
                }else{
                    item += line[i];
                }

                if ((count-1 == i)&(Quote != true)){
                    item = trimCSV(item);
                    if (item != "")
                        ItemList.append(item);
                    _lines_list.append(ItemList);
                    ItemList.clear();
                    item = "";
                }
            }

        }
    }
    close();
    return _lines_list;
}
Использование
    CsvReader *csv = new CsvReader(0,"C:/1.csv"); //
    if (csv->Open()){
        QList<QStringList> str = csv->CSVRead();
        qDebug() << str;
    }

Сайт автора: http://www.Baksik.ru
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Гость_Гость_*
сообщение 1.12.2011, 12:35
Сообщение #5





Гости








    


Цитата(vasilij-lavrov @ 18.6.2011, 14:57) *
Цитата(AD @ 7.10.2010, 9:09) *
Думаю, что может пригодиться. Подчиненная создала парсер CSV файлов на Qt. Есть просто некоторая добавка, которая может быть полезна и другим. В CSV файле можно делать однострочные комментарии с помощью символа // и многострочные комментарии с помощью /* */. Вот код:

Ага всё бы ничего да вот только он не умеет нормально парсить в соответствии с документацией ( http://ru.wikipedia.org/wiki/CSV )!!!
Весь инет прогуглил, так и не нашел правильного, пришлось самому кодить, держите кому надо:
h-file
#ifndef CSVREADER_H
#define CSVREADER_H

#include <QObject>
#include <QString>
#include <QStringList>
#include <QFile>


class QTextStream;

// Класс чтения входных CSV-файлов
class CsvReader: public QObject
{
    Q_OBJECT

private:
    QFile _file;                        // ucxoдный CSV-фaйл
    QChar _separator;                   // разделитель, по которому определяется разбивка на колонки
    QList<QStringList> _lines_list;     // массив полученный в результате разбора CSV-файла

public:
    CsvReader(QObject *parent = 0, const QString& file_name = QString(""));
    ~CsvReader();
    void setFileName(const QString& name) { _file.setFileName(name); }  // ycmaнoвka имени файла
    bool Open();                                                        // omkpыmue файла
    QList<QStringList> CSVRead();                                       // разбор файла
    void close() { if(isOpen()) _file.close(); }                        // зakpыmue файла
    bool isOpen() const { return _file.isOpen(); }                      // npoвepka открытия файла

};
#endif // CSVREADER_H
cpp-file
#include "csvreader.h"
#include <QTextStream>

CsvReader::CsvReader(QObject *parent, const QString& file_name): QObject(parent), _file(file_name), _separator(';')
{ }

CsvReader::~CsvReader()
{
    close();
}

bool CsvReader::Open(){
    if(!_file.open(QIODevice::ReadOnly | QIODevice::Text)){
        return false;
    }else
        return true;
}

//чистка значения
QString trimCSV(QString item){
    if((!item.isEmpty())&&(item[0] == QChar(34)))
        item.remove(0,1);
    if((!item.isEmpty())&&(!item.isNull())&(item[item.count()-1] == QChar(34)))
        item.remove(item.count()-1,1);
    if(!item.isEmpty())
        item = item.replace("\"\"","\"");
    return item;

}

//Paзбop файла
//в соответствии со спецификацией, подробнее: http://ru.wikipedia.org/wiki/CSV
QList<QStringList> CsvReader::CSVRead()
{
    if (_file.isOpen()){
        bool Quote = false;
        QList<QString> ItemList;
        QString item = "";
        QTextStream out(&_file);
        while(!out.atEnd()){
            QString line(out.readLine().simplified());
            int count = line.count();
            for (int i = 0;i<count;i++){
                if (line[i] == QChar(34)){
                    Quote = (Quote) ? false : true;
                }
                if ((Quote != true)&(line[i] == _separator)){
                    ItemList.append(trimCSV(item));
                    item = "";
                }else{
                    item += line[i];
                }

                if ((count-1 == i)&(Quote != true)){
                    item = trimCSV(item);
                    if (item != "")
                        ItemList.append(item);
                    _lines_list.append(ItemList);
                    ItemList.clear();
                    item = "";
                }
            }

        }
    }
    close();
    return _lines_list;
}
Использование
    CsvReader *csv = new CsvReader(0,"C:/1.csv"); //
    if (csv->Open()){
        QList<QStringList> str = csv->CSVRead();
        qDebug() << str;
    }

Сайт автора: http://www.Baksik.ru


Цитата(vasilij-lavrov @ 18.6.2011, 14:57) *
держите кому надо

Спасибо большое.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
PAFOS
  опции профиля:
сообщение 1.12.2011, 14:03
Сообщение #6


Активный участник
***

Группа: Участник
Сообщений: 258
Регистрация: 27.12.2010
Из: Дмитров
Пользователь №: 2309

Спасибо сказали: 29 раз(а)




Репутация:   8  


почему-то проигнорировали регулярки... там вашпе одной функцией можно было бы обойтись...
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
vasilij-lavrov
  опции профиля:
сообщение 1.12.2011, 14:24
Сообщение #7


Новичок


Группа: Новичок
Сообщений: 2
Регистрация: 18.6.2011
Пользователь №: 2757

Спасибо сказали: 2 раз(а)




Репутация:   1  


Цитата(PAFOS @ 1.12.2011, 15:03) *
почему-то проигнорировали регулярки... там вашпе одной функцией можно было бы обойтись...

Ну, а что сам не сделал, сделал бы да для людей выложил.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
AD
  опции профиля:
сообщение 15.2.2012, 9:58
Сообщение #8


Профессионал
*****

Группа: Участник
Сообщений: 2003
Регистрация: 4.2.2008
Из: S-Petersburg
Пользователь №: 84

Спасибо сказали: 70 раз(а)




Репутация:   17  


Цитата(vasilij-lavrov @ 18.6.2011, 15:57) *
Ага всё бы ничего да вот только он не умеет нормально парсить в соответствии с документацией ( http://ru.wikipedia.org/wiki/CSV )!!!

Спасибо за свой вариант. А в чем проявляется некорректность парсера, выложенного мной? В твоем коде не разбирался, просто посмотрел. Словами можешь описать? Заранее спасибо. Может смогу корректно исправить парсинг.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
AD
  опции профиля:
сообщение 11.4.2012, 9:58
Сообщение #9


Профессионал
*****

Группа: Участник
Сообщений: 2003
Регистрация: 4.2.2008
Из: S-Petersburg
Пользователь №: 84

Спасибо сказали: 70 раз(а)




Репутация:   17  


Так и не понял, в чем некорректность моего парсера. То, что он пропускает специфичные комментарии - это специально сделано.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
AD
  опции профиля:
сообщение 20.5.2012, 17:46
Сообщение #10


Профессионал
*****

Группа: Участник
Сообщений: 2003
Регистрация: 4.2.2008
Из: S-Petersburg
Пользователь №: 84

Спасибо сказали: 70 раз(а)




Репутация:   17  


Ау. Есть кто-нибудь из тех, кто использовал выложенный тут парсер? Так в чем недочет-то?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

2 страниц V   1 2 >
Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 15.9.2019, 15:00