This page summarizes write-side APIs and practical usage patterns for emitting CSV/TSV data.
Core Writer APIs
Use csv::make_csv_writer() for comma-delimited output and csv::make_tsv_writer() for tab-delimited output.
Writing Containers with <tt>operator<<</tt>
Any row-like container of string-convertible values can be streamed directly.
TEMPLATE_TEST_CASE("CSV/TSV Writer - operator <<", "[test_csv_operator<<]",
std::vector<std::string>, std::deque<std::string>, std::list<std::string>) {
std::stringstream output, correct_comma, correct_tab;
correct_comma << "A,B,C" << std::endl << "\"1,1\",2,3" << std::endl;
correct_tab << "A\tB\tC" << std::endl << "1,1\t2\t3" << std::endl;
auto test_row_1 = TestType({ "A", "B", "C" }),
test_row_2 = TestType({ "1,1", "2", "3" });
SECTION("CSV Writer") {
csv_writer << test_row_1 << test_row_2;
REQUIRE(output.str() == correct_comma.str());
}
SECTION("TSV Writer") {
tsv_writer << test_row_1 << test_row_2;
REQUIRE(output.str() == correct_tab.str());
}
}
TSVWriter< OutputStream > make_tsv_writer(OutputStream &out, bool quote_minimal=true)
Return a csv::TSVWriter over the output stream.
CSVWriter< OutputStream > make_csv_writer(OutputStream &out, bool quote_minimal=true)
Return a csv::CSVWriter over the output stream.
Writing Tuples and Custom Types
DelimWriter can also serialize tuples and custom types that provide a string conversion.
struct Time {
std::string hour;
std::string minute;
operator std::string() const {
std::string ret = hour;
ret += ":";
ret += minute;
return ret;
}
};
#ifndef __clang__
TEST_CASE("CSV Tuple", "[test_csv_tuple]") {
#ifdef CSV_HAS_CXX17
Time time = { "5", "30" };
#else
std::string time = "5:30";
#endif
std::stringstream output, correct_output;
csv_writer << std::make_tuple("One", 2, "Three", 4.0, time)
<< std::make_tuple("One", (short)2, "Three", 4.0f, time)
<< std::make_tuple(-1, -2.0)
<< std::make_tuple(20.2, -20.3, -20.123)
<< std::make_tuple(0.0, 0.0f, 0);
correct_output << "One,2,Three,4.0,5:30" << std::endl
<< "One,2,Three,4.0,5:30" << std::endl
<< "-1,-2.0" << std::endl
<< "20.19999,-20.30000,-20.12300" << std::endl
<< "0.0,0.0,0" << std::endl;
REQUIRE(output.str() == correct_output.str());
}
#endif
Data Reordering Workflow
For read-transform-write pipelines, csv::CSVRow supports conversion to std::vector<std::string>, which makes it straightforward to reorder/select fields before writing.
Typical flow:
- Read with
CSVReader
- Convert row to
std::vector<std::string>
- Reorder/select fields
- Emit with
CSVWriter
TEST_CASE("CSV Writer - Reorder Columns", "[test_csv_reorder]") {
auto rows = "A,B,C\r\n"
"1,2,3\r\n"
"4,5,6"_csv;
std::stringstream output, correct;
auto writer = make_csv_writer(output);
writer << std::vector<std::string>({ "C", "A" });
for (auto& row : rows) {
writer << std::vector<std::string>({
row["C"].get<std::string>(),
row["A"].get<std::string>()
});
}
correct << "C,A" << std::endl
<< "3,1" << std::endl
<< "6,4" << std::endl;
REQUIRE(output.str() == correct.str());
}