Read and write CSV data from strings or files, with proper quoting and escaping.
import vendor/csv
The parser handles quoted fields, escaped quotes (""), embedded newlines, and trailing carriage returns. Every reading function accepts optional arguments thanks to Bern's clause-based defaults.
Rows are returned as an object keyed by row number ("0", "1", …). With headers enabled (the default), each row is itself an object keyed by the header names; without headers, each row is a plain list of fields.
-- with headers (default)
#{ "0": #{ name: "Ana", age: "30" }#, "1": #{ name: "Bob", age: "25" }# }#
-- without headers / parse_csv_rows
#{ "0": ["name", "age"], "1": ["Ana", "30"], "2": ["Bob", "25"] }#
Parse CSV text. With headers on, returns rows as header-keyed objects.
csv = "name,age\nAna,30\nBob,25" rows = parse_csv(csv) rows["0"]["name"] -- Output: "Ana" rows["1"]["age"] -- Output: "25"
Parse into raw rows (lists of fields) without applying headers.
rows = parse_csv_rows("a,b\n1,2")
rows["0"]
-- Output: ["a", "b"]
rows["1"]
-- Output: ["1", "2"]
Read a file and parse it in one step (the file version of parse_csv).
rows = read_csv("people.csv")
rows["0"]["name"]
-- Output: (first person's name)
Read a file into raw rows (the file version of parse_csv_rows).
rows = read_csv_rows("data.tsv", "\t")
rows["0"]
-- Output: (first row as a list of fields)
Write a list-of-lists dataset, prefixed by the header row. Fields are quoted automatically when needed.
write_csv_from_list(
["name", "age"],
[["Ana", "30"], ["Bob", "25"]],
"out.csv"
)
-- Writes:
-- name,age
-- Ana,30
-- Bob,25
Write an indexed object of row-objects, pulling fields in the given header order.
people = #{
"0": #{ name: "Ana", age: "30" }#,
"1": #{ name: "Bob", age: "25" }#
}#
write_csv_from_objects(["name", "age"], people, "out.csv")
A full pipeline: read a file, transform a column, and write the result back out. Here we read people, increment everyone's age, and save:
import core
import strings
import vendor/csv
rows = parse_csv("name,age\nAna,30\nBob,25")
-- build the new rows as lists, in header order
out = []
loop i : [0..(length(keys(rows)) - 1)] do
r = rows["" + i]
next_age = to_int(r["age"]) + 1
out = out <> [[r["name"], from_int(next_age)]]
end
write_csv_from_list(["name", "age"], out, "people_aged.csv")
-- people_aged.csv now contains Ana,31 and Bob,26
And a quick aggregation straight from parsed rows, with core:
import core
import vendor/csv
rows = parse_csv("item,price\npen,3\nbook,12\nlamp,20")
total = 0
loop i : [0..(length(keys(rows)) - 1)] do
total = total + to_int(rows["" + i]["price"])
end
total
-- Output: 35