Skip to content

Latest commit

History

5 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

@rix/csv

CSV parser and writer for Rix.

@rix/csv is a small header-only C++ package for reading, writing, transforming, and inspecting CSV data.

It can be used independently, or through the unified @rix/rix facade.

Installation

vix add @rix/csv
vix install

Basic usage

#include<rix/csv.hpp>
#include<iostream>
#include<string>intmain()
{
const std::string input =
"name,language\n""Ada,C++\n""Gaspard,Vix\n";
const rixlib::csv::Table table = rixlib::csv::parse(input);
std::cout << "rows: " << table.size() << '\n';
for (constauto &row : table)
{
for (std::size_t i = 0; i < row.size(); ++i)
{
if (i > 0)
{
std::cout << '';
}
std::cout << row[i];
}
std::cout << '\n';
}
return0;
}

Output:

rows: 3
name language
Ada C++
Gaspard Vix

Parse CSV

const std::string input =
"name,language\n""Ada,C++\n";
const rixlib::csv::Table table = rixlib::csv::parse(input);

A table is represented as:

using Row = std::vector<std::string>;
using Table = std::vector<Row>;

So this CSV:

name,language
Ada,C++

becomes:

{
{"name", "language"},
{"Ada", "C++"}
}

Write CSV

const rixlib::csv::Table table = {
{"name", "language"},
{"Ada", "C++"},
{"Gaspard", "Vix"},
};
const std::string output = rixlib::csv::write(table);

Output:

name,language
Ada,C++
Gaspard,Vix

Write a single row

const rixlib::csv::Row row = {"Ada", "C++", "expert"};
const std::string line = rixlib::csv::write_row(row);

Output:

Ada,C++,expert

Parsing options

rixlib::csv::Options options{};
options.skip_empty_lines = true;
options.trim_whitespace = true;
constauto table = rixlib::csv::parse(input, options);

Available options include:

options.separator = ',';
options.quote_char = '"';
options.trim_whitespace = false;
options.skip_empty_lines = false;
options.skip_comments = false;
options.comment_char = '#';
options.max_field_size = 0;
options.max_fields_per_row = 0;

You can also transform fields while parsing:

rixlib::csv::Options options{};
options.field_transformer = [](std::string &field)
{
for (char &ch : field)
{
ch = static_cast<char>(std::toupper(static_cast<unsignedchar>(ch)));
}
};
constauto table = rixlib::csv::parse(input, options);

And filter rows:

rixlib::csv::Options options{};
options.row_filter = [](const rixlib::csv::Row &row)
{
return row.size() == 2;
};
constauto table = rixlib::csv::parse(input, options);

Writing options

rixlib::csv::WriteOptions options{};
options.separator = ';';
options.line_ending = "\r\n";
options.always_quote = true;
const std::string output = rixlib::csv::write(table, options);

Available write options include:

options.separator = ',';
options.quote_char = '"';
options.line_ending = "\n";
options.always_quote = false;
options.trim_before_write = false;

Load and save files

const rixlib::csv::Table table = rixlib::csv::load("data.csv");
rixlib::csv::save("output.csv", table);

Stream support

Parse from an input stream:

std::ifstream file("data.csv", std::ios::binary);
const rixlib::csv::Table table = rixlib::csv::parse(file);

Write to an output stream:

std::ofstream file("output.csv", std::ios::binary);
rixlib::csv::write_to(file, table);

Dict-style reading

The first row can be treated as a header.

constauto table = rixlib::csv::parse(
"name,language\n""Ada,C++\n""Gaspard,Vix\n");
rixlib::csv::DictReader reader{table};
for (const rixlib::csv::RowView row : reader)
{
std::cout << row["name"] << " uses " << row["language"] << '\n';
}

Output:

Ada uses C++
Gaspard uses Vix

Select columns

constauto selected = rixlib::csv::select_columns(table, {"name"});

Read a column

const std::vector<std::string> names = rixlib::csv::column(table, "name");

Filter rows

constauto filtered = rixlib::csv::filter_rows(
table,
[](const rixlib::csv::Row &row)
{
return row.size() >= 2 && row[1] == "C++";
});

Transform fields

constauto transformed = rixlib::csv::transform_fields(
table,
[](std::string &field)
{
field = "[" + field + "]";
});

Describe a table

std::cout << rixlib::csv::describe(table);

Example output:

csv::Table: 3 row(s), 2 column(s)
[header] "name" | "language"
[1] "Ada" | "C++"
[2] "Gaspard" | "Vix"

Dialect detection

constauto dialect = rixlib::csv::sniff(sample);
rixlib::csv::Options options{};
options.separator = dialect.separator;
constauto table = rixlib::csv::parse(full_text, options);

Streaming parser

Use StreamingParser when you want to process rows without storing the full table in memory.

std::size_t count = 0;
rixlib::csv::StreamingParser parser{
[&](const rixlib::csv::Row &row)
{
++count;
}};
parser.parse(input);
std::cout << "rows: " << count << '\n';

Version

std::cout << rixlib::csv::version() << '\n';

Unified Rix facade

When used through @rix/rix, the package is mounted under rix.csv.

#include<rix.hpp>intmain()
{
constauto table = rix.csv.parse("name,language\nAda,C++\n");
rix.debug.log("loaded {} rows", table.size());
return0;
}

Design

@rix/csv is header-only and keeps the data model simple.

rixlib::csv::Row
rixlib::csv::Table

The package exposes free functions such as:

rixlib::csv::parse(...)
rixlib::csv::write(...)
rixlib::csv::write_row(...)
rixlib::csv::load(...)
rixlib::csv::save(...)

The unified facade package @rix/rix can mount these functions as:

rix.csv.parse(...)
rix.csv.write(...)

Build

vix build

Run example

vix run

Tests

vix tests

License

MIT

About

Small CSV reader and writer for Vix C++ projects.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages