I\'m trying to create a code that will parse through a csv database with stock information. Currently, I have the code generated so that it will search with a keyword and pr
First a comma should be parsed as whitespace. You can do this by changing the internal std::ctype facet in the stream's locale:
struct csv_classification : std::ctype {
csv_classification() : ctype(make_table()) { }
private:
static mask* make_table() {
const mask* classic = classic_table();
static std::vector v(classic, classic + table_size);
v[','] |= space;
v[' '] &= ~space;
return &v[0];
}
};
Then set the locale using:
ifs.imbue(std::locale(ifs.getloc(), new csv_classification));
Next make a manipulator that checks to see if you're at the end of the line. If you are it sets the std::ios_base::failbit flag in the stream state. Also use internal storage to tell if the record belongs as a key or value in the map. Borrowing a bit from Dietmar...
static int row_end = std::ios_base::xalloc();
std::istream& record(std::istream& is) {
while (std::isspace(is.peek())) {
int c(is.peek());
is.ignore();
if (c == '\n') {
is.iword(row_end) = !is.iword(row_end);
is.setstate(std::ios_base::failbit);
}
}
return is;
}
Then you can do:
std::vector keys, values;
for (std::string item;;) {
if (ifs >> record >> item)
keys.push_back(item);
else if (ifs.eof())
break;
else if (ifs.iword(row_end)) {
ifs.clear();
while (ifs >> record >> item)
values.push_back(item);
}
else
break;
}
Now we need to apply both the keys and values and print them out. We can create a new algorithm for that:
template
void for_each_binary_range(Iter1 first1, Iter1 last1,
Iter2 first2, Iter2 last2, Function f)
{
assert(std::distance(first1, last1) <= std::distance(first2, last2));
while (first1 != last1) {
f(*first1++, *first2++);
}
}
Finally we do:
for_each_binary_range(std::begin(keys), std::end(keys),
std::begin(values), std::end(values),
[&] (std::string const& key, std::string const& value)
{
std::cout << key << ": " << value << std::endl;
}
Live Demo