A library for parsing, creating, and manipulating CSV data in Zig.
- Data integrity: modifications are explicit and predictable.
- Fail-fast: ambiguous or malformed input results in immediate failure.
- Low-level access: exposes internals for flexibility and control.
- Real-world compatibility: handles edge cases and non-standard CSV formats.
The design of this library is guided by the principles outlined in the CSV Parser Philosophy document, which emphasizes data integrity, fail-fast behavior, and low-level access to parsed data. This design approach ensures the library is compatible with real-world CSV data while avoiding ambiguity in parsing.
First, add the dependency to your build.zig.zon:
zig fetch --save git+https://github.com/DISTREAT/zig-csvThen, add the package to your build.zig:
constzig_csv=b.dependency("zig_csv", .{});
exe.root_module.addImport("zig_csv", zig_csv.module("zig_csv"));The library provides two primary types for working with CSV data:
StructuredTable and Table.
The differences between them are as follows:
StructuredTablerequires a predefined schema, allowing for type-safe parsing and manipulation of CSV data.Tableoffers a more flexible approach, enabling dynamic handling of CSV data without a predefined schema.
The StructuredTable allows you to define a schema for your CSV data,
enabling type-safe parsing and manipulation.
conststd=@import("std");
constcsv=@import("zig_csv");
constallocator=std.heap.page_allocator;
// Define a schema for the CSV dataconstAnimal=struct {
id: i32,
name: []constu8,
happy: ?bool,
};
// Parse CSV data into a StructuredTablevartable=csv.StructuredTable(Animal).init(
allocator,
csv.LexerSettings.default()
);
defertable.deinit();
trytable.parse(
\\id,name,happy\\1,dog,\\2,cat,\\3,bird,
);
// Modify the name of the animal with id 2for (0..table.getRowCount()) |index| {
// Retrieve the row at the current index.constrow=trytable.getRow(index);
if (row==.@"error") {
// If the row structure doesn't match the schema, handle the error.break;
}
// Access the parsed Animal struct from the row.varanimal=row.ok.value;
// Look for the animal with id == 2.if (animal.id!=2) continue;
// Change the animal's name to "mouse".animal.name="mouse";
// Attempt to write the modified struct back to the table.constresult=trytable.editRow(index, animal);
if (result==.@"error") {
// If the new struct doesn't match the schema, handle the error.
}
// Stop after editing the first matching row.break;
}
// Export the table back to CSVconstexported_csv=trytable.exportCSV(allocator);
deferallocator.free(exported_csv);
std.debug.print("Exported CSV:\n{s}\n", .{exported_csv});
// id,name,happy// 1,dog,// 2,mouse,// 3,bird,The Table type provides a flexible way to work with CSV data without a predefined schema.
conststd=@import("std");
constcsv=@import("zig_csv");
constallocator=std.heap.page_allocator;
// Parse CSV datavartable=csv.Table.init(allocator, csv.LexerSettings.default());
defertable.deinit();
trytable.parse(
\\id,animal,color\\1,cat,black\\2,dog,brown\\3,bird,blue
);
// Change the color of the dog to "white"constanimal_col= (trytable.findColumnIndexesByValue(allocator, 0, "animal"))[0];
constdog_row= (trytable.findRowIndexesByValue(allocator, animal_col, "dog"))[0];
constcolor_col= (trytable.findColumnIndexesByValue(allocator, 0, "color"))[0];
trytable.replaceValue(dog_row, color_col, "white");
// Add a new animalconstnew_row=trytable.insertEmptyRow(null);
trytable.replaceValue(new_row, animal_col, "fish");
trytable.replaceValue(new_row, color_col, "gold");
// Export the table back to CSVconstexported=trytable.exportCSV(allocator);
deferallocator.free(exported);
std.debug.print("Exported CSV:\n{s}\n", .{exported});
// id,animal,color// 1,cat,black// 2,dog,white// 3,bird,blue// ,fish,goldMore examples can be found in src/tests.zig.
The documentation is available online,
or can be built locally using zig build docs.