Within the specified limitations, I think I would do something like this:
#include <locale> #include <iostream> #include <sstream> #include <string> #include <vector> #include <iterator> // A ctype that classifies only comma and new-line as "white space": struct field_reader : std::ctype<char> { field_reader() : std::ctype<char>(get_table()) {} static std::ctype_base::mask const* get_table() { static std::vector<std::ctype_base::mask> rc(table_size, std::ctype_base::mask()); rc[','] = std::ctype_base::space; rc['\n'] = std::ctype_base::space; return &rc[0]; } }; // A struct to hold one record from the file: struct record { std::string key, name, desc, url, zip, date, number; friend std::istream &operator>>(std::istream &is, record &r) { return is >> r.key >> r.name >> r.desc >> r.url >> r.zip >> r.date >> r.number; } friend std::ostream &operator<<(std::ostream &os, record const &r) { return os << "key: " << r.key << "\nname: " << r.name << "\ndesc: " << r.desc << "\nurl: " << r.url << "\nzip: " << r.zip << "\ndate: " << r.date << "\nnumber: " << r.number; } }; int main() { std::stringstream input("23456, The End is Near, A silly description that makes no sense, http://www.example.com, 45332, 5th July 1998 Sunday, 45.332"); // use our ctype facet with the stream: input.imbue(std::locale(std::locale(), new field_reader())); // read in all our records: std::istream_iterator<record> in(input), end; std::vector<record> records{ in, end }; // show what we read: std::copy(records.begin(), records.end(), std::ostream_iterator<record>(std::cout, "\n")); }
It is, without a doubt, longer than most others, but it is all broken up into small, mostly reusable pieces. After you have other parts in place, the code for reading data is trivial:
std::vector<record> records{ in, end };
Another point that I find convincing: when I first compiled the code, it also worked correctly (and I find this usual procedure for this programming style).
source share