Chapter 46. CSV-formatted data

#include <x/csv.H>

for (size_t row=0; row<3; row++)
{
    std::vector<std::string> v;

    for (size_t col=0; col<5; col++)
    {
        std::ostringstream o;

        o << row*10 + col;

        v.push_back(o.str());
    }

    x::tocsv(v.begin(), v.end(),
         std::ostreambuf_iterator<char>(std::cout));
    std::cout << std::endl;
}

The first two parameters to x::tocsv() are a beginning and and ending input iterator which iterate over strings. x::tocsv() formats this input sequence using a "comma-separated-value" format.

The strings may contain any characters, including newlines. Therefore, parsing a "comma-separated-value" format cannot be done one line at a time. A character input iterator is required with x::fromcsv():

#include <x/csv.H>

std::istream &i;

// ...

std::istreambuf_iterator<char> b(i), e;

while (b != e)
{
    std::cout << "Line: " << std::endl;

    std::vector<std::string> rows;

    b=x::fromcsv(b, e, rows);

    if (b == e || *b++ != '\n')
    {
        std::cerr << "Formatting error" << std::endl;
    }
    else
    {
        for (std::vector<std::string>::const_iterator
                 b=rows.begin(), e=rows.end(); b != e; ++b)
        {
            std::cout << "   Col: " << *b << std::endl;
        }
    }
}

This example shows the proper way to parse "comma-separated-values":

#include <x/csv.H>

std::istream &i;

// ...
std::map<std::string, size_t> headers;

std::istreambuf_iterator<char> b(i), e;

b=x::csvheaderrow(b, e, headers);

if (b == e || *b++ != '\n')
{
    std::cerr << "Formatting error" << std::endl;
}
else
{
    // ...

x::csvheaderrow() uses x::fromcsv() to parse a CSV header line, placing the column names into a map keyed by the column name, with the value being the 0-based column number.