diff --git a/core/encoding/csv/csv.odin b/core/encoding/csv/csv.odin index 580767078..04a776fcd 100644 --- a/core/encoding/csv/csv.odin +++ b/core/encoding/csv/csv.odin @@ -2,7 +2,7 @@ package csv // @note(zh): Encoding utility for csv files // You may use the provided struct to build your csv dynamically. -// If you have a string with the whole content already, just use write_raw. +// If you have a string with the whole content already, just use write_file_raw to write it to a file. // You are able to read the csv with the headers included in the data or omitted by providing // a bool parameter to the proc as shown down below. // Example useage: @@ -15,20 +15,33 @@ main :: proc() { file_name := "test.csv"; // Write file and read with the headers omitted - if isOkWrite := write(file_name, &ctx); isOkWrite { - if content, row_count, isOkRead := read(file_name, DELIMITER, true); isOkRead { - fmt.println("Column count(no headers): ", row_count); + if isOkWrite := write_file(file_name, &ctx); isOkWrite { + if content, row_count, isOkRead := read_file(file_name, DELIMITER, true); isOkRead { + fmt.println("Row count(no headers): ", row_count); fmt.println(content); } } // Write file and read with the headers being read as well - if isOkWrite := write(file_name, &ctx); isOkWrite { - if content, row_count, isOkRead := read(file_name); isOkRead { - fmt.println("Column count(with headers): ", row_count); + if isOkWrite := write_file(file_name, &ctx); isOkWrite { + if content, row_count, isOkRead := read_file(file_name); isOkRead { + fmt.println("Row count(with headers): ", row_count); fmt.println(content); } } + + // Write slice to a csv string + csv_string_data: [9]string = {"aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii"}; + col_count := 3; + csv_string := write_string(csv_string_data[:], col_count); + fmt.println(csv_string); + + // Read data into a slice when you have read the csv file yourself + csv_data := "aaa, bbb, ccc\n ddd, eee, fff\n ggg, hhh, iii"; + if content, row_count, isOkRead := read_string(csv_data); isOkRead { + fmt.println("Row count(from string): ", row_count); + fmt.println(content); + } } */ @@ -45,7 +58,17 @@ LF :: "\n"; CRLF :: "\r\n"; DELIMITER :: ","; -write :: proc(path: string, ctx: ^CSV) -> bool { +write_string :: proc(data: []string, col_count: int, delimiter := DELIMITER, line_ending := LF) -> string { + b := strings.make_builder(); + for i := 0; i < len(data); i += 1 { + if i >= col_count && i % col_count == 0 do strings.write_string(&b, line_ending); + strings.write_string(&b, data[i]); + if len(data) - i > 1 do strings.write_string(&b, delimiter); + } + return strings.to_string(b); +} + +write_file :: proc(path: string, ctx: ^CSV) -> bool { b := strings.make_builder(); defer strings.destroy_builder(&b); @@ -59,10 +82,10 @@ write :: proc(path: string, ctx: ^CSV) -> bool { } strings.write_string(&b, ctx.line_ending); } - return write_raw(path, b.buf[:]); + return write_file_raw(path, b.buf[:]); } -write_raw :: proc(path: string, data: []byte) -> bool { +write_file_raw :: proc(path: string, data: []byte) -> bool { file, err := os.open(path, os.O_RDWR | os.O_CREATE | os.O_TRUNC); if err != os.ERROR_NONE do return false; defer os.close(file); @@ -71,13 +94,14 @@ write_raw :: proc(path: string, data: []byte) -> bool { return true; } -read :: proc(path: string, delimiter := DELIMITER, skip_header := false) -> (content: []string, row_count: int, is_ok: bool) { - if bytes, isOk := os.read_entire_file(path); isOk { +read_string ::proc(data: string, delimiter := DELIMITER, skip_header := false) -> (content: []string, row_count: int, is_ok: bool) { + if data != "" { cols: [dynamic]string; defer delete(cols); content: [dynamic]string; row_count := 0; prev_index := 0; + bytes := ([]byte)(data); for i := 0; i < len(bytes); i += 1 { if bytes[i] == '\n' { append(&cols, string(bytes[prev_index:i])); @@ -101,6 +125,14 @@ read :: proc(path: string, delimiter := DELIMITER, skip_header := false) -> (con for col in cols do append(&content, ..strings.split(col, delimiter)); if skip_header do return content[row_count:], row_count - 1, true; else do return content[:], row_count, true; + } else { + return nil, -1, false; + } +} + +read_file :: proc(path: string, delimiter := DELIMITER, skip_header := false) -> (content: []string, row_count: int, is_ok: bool) { + if bytes, isOk := os.read_entire_file(path); isOk { + return read_string(string(bytes), delimiter, skip_header); } return nil, -1, false; } \ No newline at end of file