diff --git a/csv.go b/csv.go index 1ae8f49..c49469d 100644 --- a/csv.go +++ b/csv.go @@ -1,11 +1,38 @@ package scriptx import ( + "bufio" "encoding/csv" "errors" "io" ) +type Splitter interface { + Split(line string, n int) []string +} + +// ToCSV is a filter function that reads the source as a series of lines, splits them +// into tokens using the passed in Splitter, and writes them to the output as a CSV. +func ToCSV(splitter Splitter) func(io.Reader, io.Writer) error { + return func(r io.Reader, w io.Writer) error { + csvWriter := csv.NewWriter(w) + + scnr := bufio.NewScanner(r) + for scnr.Scan() { + line := scnr.Text() + if err := csvWriter.Write(splitter.Split(line, -1)); err != nil { + return err + } + } + if err := scnr.Err(); err != nil { + return err + } + + csvWriter.Flush() + return nil + } +} + // CSVColumn is a filter function that reads the source as a CSV file and extracts the cell // values of the named column, excluding the header itself. If the column cannot be found, // the filter will produce nothing. If the column index is beyond the number of columns diff --git a/csv_test.go b/csv_test.go index 5127152..93b7175 100644 --- a/csv_test.go +++ b/csv_test.go @@ -1,6 +1,7 @@ package scriptx_test import ( + "regexp" "testing" "github.com/bitfield/script" @@ -42,3 +43,17 @@ func ExampleCSVColumn() { // banana // cherry } + +func ExampleToCSV() { + script.Slice([]string{ + "letter fruit word", + "a apple alpha", + "b banana bravo", + "c cherry charlie", + }).Filter(scriptx.ToCSV(regexp.MustCompile(`\s+`))).Stdout() + // Output: + // letter,fruit,word + // a,apple,alpha + // b,banana,bravo + // c,cherry,charlie +}