解析Qt中的csv文件

时间:2014-12-05 14:55:54

标签: c++ qt csv qt5 qfile

是否有人熟悉如何解析csv文件并将其放入字符串列表中。现在我正在整个csv文件并放入字符串列表。我想弄清楚是否有办法只获得第一列。

#include "searchwindow.h"
#include <QtGui/QApplication>

#include <QApplication>
#include <QStringList>
#include <QLineEdit>
#include <QCompleter>
#include <QHBoxLayout>
#include <QWidget>
#include <QLabel>

#include <qfile.h>
#include <QTextStream>


int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QWidget *widget = new QWidget();
    QHBoxLayout *layout = new QHBoxLayout();

    QStringList wordList;

    QFile f("FlightParam.csv");
    if (f.open(QIODevice::ReadOnly))
    {
        //file opened successfully
        QString data;
        data = f.readAll();
        wordList = data.split(',');

        f.close();
    }

    QLabel *label = new QLabel("Select");
    QLineEdit *lineEdit = new QLineEdit;
    label->setBuddy(lineEdit);

    QCompleter *completer = new QCompleter(wordList);
    completer->setCaseSensitivity(Qt::CaseInsensitive); //Make caseInsensitive selection

    lineEdit->setCompleter(completer);

    layout->addWidget(label);
    layout->addWidget(lineEdit);

    widget->setLayout(layout);
    widget->showMaximized();

    return a.exec();
}

6 个答案:

答案 0 :(得分:17)

你去了:

FlightParam.csv

1,2,3,
4,5,6,
7,8,9,

的main.cpp

#include <QFile>
#include <QStringList>
#include <QDebug>

int main()
{
    QFile file("FlightParam.csv");
    if (!file.open(QIODevice::ReadOnly)) {
        qDebug() << file.errorString();
        return 1;
    }

    QStringList wordList;
    while (!file.atEnd()) {
        QByteArray line = file.readLine();
        wordList.append(line.split(',').first());
    }

    qDebug() << wordList;

    return 0;
}

main.pro

TEMPLATE = app
TARGET = main
QT = core
SOURCES += main.cpp

构建并运行

qmake && make && ./main

输出

("1", "4", "7")

答案 1 :(得分:7)

您正在寻找的是QTextStream课程。它提供了各种用于读写文件的接口。

一个简单的例子:

QStringList firstColumn;
QFile f1("h:/1.txt");
f1.open(QIODevice::ReadOnly);
QTextStream s1(&f1);
while (!s1.atEnd()){
  QString s=s1.readLine(); // reads line from file
  firstColumn.append(s.split(",").first()); // appends first column to list, ',' is separator
}
f1.close();

或者是的,你可以做类似这样的结果:

wordList = f.readAll().split(QRegExp("[\r\n]"),QString::SkipEmptyParts); //reading file and splitting it by lines
for (int i=0;i<wordList.count();i++) 
   wordList[i]=wordlist[i].split(",").first(); // replacing whole row with only first value
f.close();    

答案 2 :(得分:6)

这是我经常使用的代码。我是作者,考虑这个原样,公共领域。它具有与CodeLurker's code类似的功能集和概念,除了状态机的表示方式不同,代码有点短。

bool readCSVRow (QTextStream &in, QStringList *row) {

    static const int delta[][5] = {
        //  ,    "   \n    ?  eof
        {   1,   2,  -1,   0,  -1  }, // 0: parsing (store char)
        {   1,   2,  -1,   0,  -1  }, // 1: parsing (store column)
        {   3,   4,   3,   3,  -2  }, // 2: quote entered (no-op)
        {   3,   4,   3,   3,  -2  }, // 3: parsing inside quotes (store char)
        {   1,   3,  -1,   0,  -1  }, // 4: quote exited (no-op)
        // -1: end of row, store column, success
        // -2: eof inside quotes
    };

    row->clear();

    if (in.atEnd())
        return false;

    int state = 0, t;
    char ch;
    QString cell;

    while (state >= 0) {

        if (in.atEnd())
            t = 4;
        else {
            in >> ch;
            if (ch == ',') t = 0;
            else if (ch == '\"') t = 1;
            else if (ch == '\n') t = 2;
            else t = 3;
        }

        state = delta[state][t];

        switch (state) {
        case 0:
        case 3:
            cell += ch;
            break;
        case -1:
        case 1:
            row->append(cell);
            cell = "";
            break;
        }

    }

    if (state == -2)
        throw runtime_error("End-of-file found while inside quotes.");

    return true;

}
  • 参数:inQTextStream
  • 参数:rowQStringList将收到该行。
  • 如果已读取行,则返回true,如果是EOF,则返回false
  • 如果发生错误,则抛出:std::runtime_error

它解析Excel样式的CSV,适当地处理引号和双引号,并允许字段中的换行符。只要使用QFile::Text打开文件,就可以正确处理Windows和Unix行结尾。我不认为Qt支持老式的Mac行结尾,并且这不支持二进制模式的非翻译行结尾,但是在大多数情况下,这应该不是问题。

其他说明:

  • 与CodeLurker的实现不同,如果在引号内触及EOF,则故意失败。如果你在状态表中将-2改为-1,那么它将是宽容的。
  • 解析x"y"zxyz,不确定中间字符串引号的规则是什么。我不知道这是否正确。
  • 性能和内存特性与CodeLurker相同(即非常好)。
  • 不支持unicode(converts to ISO-5589-1),但更改为QChar应该是微不足道的。

示例:

QFile csv(filename);
csv.open(QFile::ReadOnly | QFile::Text);

QTextStream in(&csv);
QStringList row;
while (readCSVRow(in, &row))
    qDebug() << row;

答案 3 :(得分:5)

有人可能更喜欢这样做:

QStringList MainWindow::parseCSV(const QString &string)
{
    enum State {Normal, Quote} state = Normal;
    QStringList fields;
    QString value;

    for (int i = 0; i < string.size(); i++)
    {
        const QChar current = string.at(i);

        // Normal state
        if (state == Normal)
        {
            // Comma
            if (current == ',')
            {
                // Save field
                fields.append(value.trimmed());
                value.clear();
            }

            // Double-quote
            else if (current == '"')
            {
                state = Quote;
                value += current;
            }

            // Other character
            else
                value += current;
        }

        // In-quote state
        else if (state == Quote)
        {
            // Another double-quote
            if (current == '"')
            {
                if (i < string.size())
                {
                    // A double double-quote?
                    if (i+1 < string.size() && string.at(i+1) == '"')
                    {
                        value += '"';

                        // Skip a second quote character in a row
                        i++;
                    }
                    else
                    {
                        state = Normal;
                        value += '"';
                    }
                }
            }

            // Other character
            else
                value += current;
        }
    }

    if (!value.isEmpty())
        fields.append(value.trimmed());

    // Quotes are left in until here; so when fields are trimmed, only whitespace outside of
    // quotes is removed.  The quotes are removed here.
    for (int i=0; i<fields.size(); ++i)
        if (fields[i].length()>=1 && fields[i].left(1)=='"')
        {
            fields[i]=fields[i].mid(1);
            if (fields[i].length()>=1 && fields[i].right(1)=='"')
                fields[i]=fields[i].left(fields[i].length()-1);
        }

    return fields;
}
  • 功能强大:处理带引号的引用材料,双引号(表示双引号字符)和空格右对
  • 灵活:如果忘记了最后一个字符串的最后一个引号,并且处理更复杂的CSV文件,则不会失败;让你一次处理一行,而不必先在内存中读取整个文件
  • 简单:只需在您的代码中删除此状态机,右键单击QtCreator中的函数名称,然后选择Refactor |添加私人声明,你好2去。
  • Performant:比在每个角色上执行RegEx预先更快地准确处理CSV行
  • 方便:不需要外部库
  • 易于阅读:代码非常直观,万一需要修改它。

编辑:我终于得到了这个来修剪字段之前和之后的空格。引号内没有修剪空格或逗号。否则,从字段的开头和结尾剪切所有空格。在对此进行了一段时间的困惑之后,我想到引号可以留在场地周围;因此可以修剪所有字段。这样,只删除引号之前和之后的空格。然后添加最后一步,去除以引号开头和结尾的字段的引号。

这是一个或多或少具有挑战性的测试案例:

QStringList sl=
{
    "\"one\"",
    "  \" two \"\"\"  , \" and a half  ",
    "three  ",
    "\t  four"
};

for (int i=0; i < sl.size(); ++i)
    qDebug() << parseCSV(sl[i]);

这对应于文件

"one"
 " two """  , " and a half  
three  
<TAB>  four

其中&lt; TAB&gt;表示制表符;每行依次输入parseCSV()。不要写这样的.csv文件!

它的输出是(其中qDebug()用\"表示字符串中的引号并将内容放在引号和parens中:

("one")
(" two \"", " and a half")
("three")
("four")

您可以观察到引用和额外空格保留在项目#34; 2&#34;的引号内。在&#34;半&#34;的格式错误的情况下,引用前的空格和最后一个字后的空格被删除;但其他人则没有。此例程中缺少终端空间可能表示缺少终端报价。在不开始或结束它的字段中的引号仅被视为字符串的一部分。如果一个字段没有启动,则不会从字段末尾删除引号。要在此检测错误,只需检查以引号开头但不以一个结尾的字段;和/或包含引号但在最后一个循环中不以一个开头和结尾的一个。

我知道,对于你的测试案例来说,需要的不仅仅是;但是对于这个问题仍然是一个可靠的答案 - 也许对其他人来说也是如此。

改编自: https://github.com/hnaohiro/qt-csv/blob/master/csv.cpp

答案 4 :(得分:4)

尝试使用qtcsv库来读取和编写csv文件。例如:

#include <QList>
#include <QStringList>
#include <QDir>
#include <QDebug>

#include "qtcsv/stringdata.h"
#include "qtcsv/reader.h"
#include "qtcsv/writer.h"

int main()
{
    // prepare data that you want to save to csv-file
    QStringList strList;
    strList << "one" << "two" << "three";

    QtCSV::StringData strData;
    strData.addRow(strList);
    strData.addEmptyRow();
    strData << strList << "this is the last row";

    // write to file
    QString filePath = QDir::currentPath() + "/test.csv";
    QtCSV::Writer::write(filePath, strData);

    // read data from file
    QList<QStringList> readData = QtCSV::Reader::readToList(filePath);
    for ( int i = 0; i < readData.size(); ++i )
    {
        qDebug() << readData.at(i).join(",");
    }

    return 0;
}

我试着让它小巧易用。有关库文档和其他代码示例,请参阅Readme文件。

答案 5 :(得分:1)

lines = data.split('\n');

然后

for line in lines
   column1.add(line.split(',')[0])

我不确定添加函数是否存在以添加到数组中 - 让我们调用第1列