如何在C ++中读取和解析CSV文件?
我需要在C ++中加载和使用CSV文件数据。在这一点上,它真的只是一个逗号分隔的解析器(即不必担心转义新行和逗号)。主要需要一个逐行解析器,它将在每次调用方法时为下一行返回一个向量。
I need to load and use CSV file data in C++. At this point it can really just be a comma-delimited parser (ie don't worry about escaping new lines and commas). The main need is a line-by-line parser that will return a vector for the next line each time the method is called.
我发现这篇文章看起来很有前途:
http://www.boost.org/doc /libs/1_35_0/libs/spirit/example/fundamental/list_parser.cpp
I found this article which looks quite promising: http://www.boost.org/doc/libs/1_35_0/libs/spirit/example/fundamental/list_parser.cpp
我从来没有使用过Boost的精神,但愿意尝试。但是只有没有一个更直接的解决方案,我可以忽略。
I've never used Boost's Spirit, but am willing to try it. But only if there isn't a more straightforward solution I'm overlooking.
如果你不关心转义逗号和换行符,
,并且不能将逗号和换行符嵌入引号(如果您不能转义,则...)
那么它只有三行代码(OK 14 - >但它只有15个读取整个文件)。
If you don't care about escaping comma and newline,
AND you can't embed comma and newline in quotes (If you can't escape then...)
then its only about three lines of code (OK 14 ->But its only 15 to read the whole file).
std::vector<std::string> getNextLineAndSplitIntoTokens(std::istream& str)
{
std::vector<std::string> result;
std::string line;
std::getline(str,line);
std::stringstream lineStream(line);
std::string cell;
while(std::getline(lineStream,cell, ','))
{
result.push_back(cell);
}
return result;
}
我只创建一个表示行的类。
然后流入该对象:
I would just create a class representing a row.
Then stream into that object:
#include <iterator>
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <string>
class CSVRow
{
public:
std::string const& operator[](std::size_t index) const
{
return m_data[index];
}
std::size_t size() const
{
return m_data.size();
}
void readNextRow(std::istream& str)
{
std::string line;
std::getline(str, line);
std::stringstream lineStream(line);
std::string cell;
m_data.clear();
while(std::getline(lineStream, cell, ','))
{
m_data.push_back(cell);
}
}
private:
std::vector<std::string> m_data;
};
std::istream& operator>>(std::istream& str, CSVRow& data)
{
data.readNextRow(str);
return str;
}
int main()
{
std::ifstream file("plop.csv");
CSVRow row;
while(file >> row)
{
std::cout << "4th Element(" << row[3] << ")\n";
}
}
但是通过一些工作,我们可以在技术上创建一个迭代器:
But with a little work we could technically create an iterator:
class CSVIterator
{
public:
typedef std::input_iterator_tag iterator_category;
typedef CSVRow value_type;
typedef std::size_t difference_type;
typedef CSVRow* pointer;
typedef CSVRow& reference;
CSVIterator(std::istream& str) :m_str(str.good()?&str:NULL) { ++(*this); }
CSVIterator() :m_str(NULL) {}
// Pre Increment
CSVIterator& operator++() {if (m_str) { if (!((*m_str) >> m_row)){m_str = NULL;}}return *this;}
// Post increment
CSVIterator operator++(int) {CSVIterator tmp(*this);++(*this);return tmp;}
CSVRow const& operator*() const {return m_row;}
CSVRow const* operator->() const {return &m_row;}
bool operator==(CSVIterator const& rhs) {return ((this == &rhs) || ((this->m_str == NULL) && (rhs.m_str == NULL)));}
bool operator!=(CSVIterator const& rhs) {return !((*this) == rhs);}
private:
std::istream* m_str;
CSVRow m_row;
};
int main()
{
std::ifstream file("plop.csv");
for(CSVIterator loop(file); loop != CSVIterator(); ++loop)
{
std::cout << "4th Element(" << (*loop)[3] << ")\n";
}
}