Files
sqlitebrowser/src/csvparser.cpp
Peinthor Rene 97e2025cc9 cvsparser: Newly implemented CSV Parser
Moved parser into it's own class
This parser now proper supports new lines in quoted text
and returns a QVector<QStringList> result.
2014-09-02 18:05:04 +02:00

143 lines
3.4 KiB
C++

#include "csvparser.h"
#include <QTextStream>
#include <algorithm>
CSVParser::CSVParser(bool trimfields, const QChar& fieldseparator, const QChar& quotechar)
: m_bTrimFields(trimfields)
, m_cFieldSeparator(fieldseparator)
, m_cQuoteChar(quotechar)
, m_pCSVProgress(0)
, m_nBufferSize(4096)
{
}
CSVParser::~CSVParser()
{
delete m_pCSVProgress;
}
namespace {
inline void addColumn(QStringList& r, QString& field, bool trim)
{
if(trim)
r << field.trimmed();
else
r << field;
field.clear();
}
}
bool CSVParser::parse(QTextStream& stream, int64_t nMaxRecords)
{
m_vCSVData.clear();
m_nColumns = 0;
ParseStates state = StateNormal;
QString fieldbuf;
QStringList record;
if(m_pCSVProgress)
m_pCSVProgress->start();
while(!stream.atEnd())
{
QString sBuffer = stream.read(m_nBufferSize);
for(QString::iterator it = sBuffer.begin(); it != sBuffer.end(); ++it)
{
QChar c = *it;
switch(state)
{
case StateNormal:
{
if(c == m_cFieldSeparator)
{
addColumn(record, fieldbuf, m_bTrimFields);
}
else if(c == m_cQuoteChar)
{
state = StateInQuote;
}
else if(c == '\r')
{
// look ahead to check for newline
QString::iterator nit = it + 1;
if(nit != sBuffer.end() && *nit != '\n')
fieldbuf.append(c);
}
else if(c == '\n')
{
addColumn(record, fieldbuf, m_bTrimFields);
addRow(record);
}
else
{
fieldbuf.append(c);
}
}
break;
case StateInQuote:
{
if(c == m_cQuoteChar)
{
state = StateEndQuote;
}
else
{
fieldbuf.append(c);
}
}
break;
case StateEndQuote:
{
if(c == m_cQuoteChar)
{
state = StateInQuote;
fieldbuf.append(c);
}
else if(c == m_cFieldSeparator)
{
state = StateNormal;
addColumn(record, fieldbuf, m_bTrimFields);
}
else if(c == '\n')
{
state = StateNormal;
addColumn(record, fieldbuf, m_bTrimFields);
addRow(record);
}
else
{
state = StateNormal;
fieldbuf.append(c);
}
}
break;
}
if(nMaxRecords != -1 && m_vCSVData.size() >= nMaxRecords)
return true;
}
if(m_pCSVProgress && m_vCSVData.size() % 100 == 0)
{
if(!m_pCSVProgress->update(stream.pos()))
return false;
}
}
if(!fieldbuf.isEmpty())
{
addColumn(record, fieldbuf, m_bTrimFields);
addRow(record);
}
if(m_pCSVProgress)
m_pCSVProgress->end();
return state == StateNormal;
}