From 3e552428a58ae15811c4d7b25372028b118e2716 Mon Sep 17 00:00:00 2001 From: PhatPhuckDave Date: Sat, 15 Nov 2025 15:39:49 +0100 Subject: [PATCH] Improve the csv parser by reading header and assigning values to their header So we have things like row[1] AND ALSO row["foobar"] And also row.foobar of course --- processor/processor.go | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/processor/processor.go b/processor/processor.go index 8fc54ed..72df100 100644 --- a/processor/processor.go +++ b/processor/processor.go @@ -223,12 +223,16 @@ end --- --- @param csv string The CSV text to parse. --- @param delimiter string? The field delimiter (default: ","). ---- @return table A table (array) of rows; each row is a table (array) of string fields. -function fromCSV(csv, delimiter) +--- @param hasHeaders boolean? If true, first row is treated as headers and rows can be accessed by header name (default: false). +--- @return table A table (array) of rows; each row is a table with numeric indices and optionally header-named keys. +function fromCSV(csv, delimiter, hasHeaders) if delimiter == nil then delimiter = "," end - local rows = {} + if hasHeaders == nil then + hasHeaders = false + end + local allRows = {} local fields = {} local field = {} @@ -254,7 +258,7 @@ function fromCSV(csv, delimiter) elseif c == '\r' or c == '\n' then table.insert(fields, table.concat(field)) field = {} - table.insert(rows, fields) + table.insert(allRows, fields) fields = {} if c == '\r' and i < len and csv:sub(i + 1, i + 1) == '\n' then i = i + 2 @@ -286,7 +290,7 @@ function fromCSV(csv, delimiter) elseif c == '\r' or c == '\n' then table.insert(fields, table.concat(field)) field = {} - table.insert(rows, fields) + table.insert(allRows, fields) fields = {} state = STATE_DEFAULT if c == '\r' and i < len and csv:sub(i + 1, i + 1) == '\n' then @@ -303,10 +307,27 @@ function fromCSV(csv, delimiter) if #field > 0 or #fields > 0 then table.insert(fields, table.concat(field)) - table.insert(rows, fields) + table.insert(allRows, fields) end - return rows + if hasHeaders and #allRows > 0 then + local headers = allRows[1] + local rows = {} + for i = 2, #allRows do + local row = {} + local dataRow = allRows[i] + for j = 1, #dataRow do + row[j] = dataRow[j] + if headers[j] ~= nil and headers[j] ~= "" then + row[headers[j]] = dataRow[j] + end + end + table.insert(rows, row) + end + return rows + end + + return allRows end --- Converts a table of rows back to CSV text format (RFC 4180 compliant). @@ -676,7 +697,7 @@ STRING FUNCTIONS: format(s, ...) - Formats string using Lua string.format trim(s) - Removes leading/trailing whitespace strsplit(inputstr, sep) - Splits string by separator (default: whitespace) - fromCSV(csv, delimiter) - Parses CSV text into rows of fields (delimiter defaults to ",") + fromCSV(csv, delimiter, hasHeaders) - Parses CSV text into rows of fields (delimiter defaults to ",", hasHeaders defaults to false) toCSV(rows, delimiter) - Converts table of rows to CSV text format (delimiter defaults to ",") num(str) - Converts string to number (returns 0 if invalid) str(num) - Converts number to string