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 CVSRow
{
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,CVSRow& data)
{
data.readNextRow(str);
return str;
}
int main()
{
std::ifstream file("plop.csv");
CVSRow row;
while(file >> row)
{
std::cout << "4th Element(" << row[3] << ")\n";
}
}
But with a little work we could technically create an iterator:
class CVSIterator
{
public:
typedef std::input_iterator_tag iterator_category;
typedef CVSRow value_type;
typedef std::size_t difference_type;
typedef CVSRow* pointer;
typedef CVSRow& reference;
CVSIterator(std::istream& str) :m_str(str.good()?&str:NULL) { ++(*this); }
CVSIterator() :m_str(NULL) {}
// Pre Increment
CVSIterator& operator++() {if (m_str) { (*m_str) >> m_row;m_str = m_str->good()?m_str:NULL;}return *this;}
// Post increment
CVSIterator operator++(int) {CVSIterator tmp(*this);++(*this);return tmp;}
CVSRow const& operator*() const {return m_row;}
CVSRow const* operator->() const {return &m_row;}
bool operator==(CVSIterator const& rhs) {return ((this == &rhs) || ((this->m_str == NULL) && (rhs.m_str == NULL)));}
bool operator!=(CVSIterator const& rhs) {return !((*this) == rhs);}
private:
std::istream* m_str;
CVSRow m_row;
};
int main()
{
std::ifstream file("plop.csv");
for(CVSIterator loop(file);loop != CVSIterator();++loop)
{
std::cout << "4th Element(" << (*loop)[3] << ")\n";
}
}