Documentation ¶
Overview ¶
Package csvbuddy implements a convenient interface for encoding and decoding CSV files.
Only slices of structs can be encoded and decoded because CSV is defined as a list of records.
Every exported struct field is interpreted as a CSV column. Struct fields are automatically mapped by name to a CSV column. Use the "csv" struct field tag to customize how each field is marshaled.
// StructA demonstrates CSV struct field tags. type StructA struct { // The first param is always the name, which can be empty. // Default is the name of the field. Name string `csv:"name"` // Exported fields with name "-" are ignored. Ignored int `csv:"-"` // Use base to set the integer base. Default is 10. Hex uint `csv:"addr,base=16"` // Use prec and fmt to set floating point precision and format. Default is -1 and 'f'. Flt float64 `csv:"flt,prec=6,fmt=E"` // Inline structs with inline tag. // Any csv fields in the inlined struct are also (un)marshaled. // Beware of naming clashes. B StructB `csv:",inline"` // Embedded structs do not need the inline tag. StructC }
The following struct field types are supported: bool, int[8, 16, 32, 64], uint[8, 16, 32, 64], float[32, 64], complex[64, 128], []byte, string, encoding.TextMarshaler, encoding.TextUnmarshaler. Other values produce an error.
Pointers to any of the above types are interpreted as optional types. Optional types are decoded if the parsed field is not an empty string, and they are encoded as an empty string if the pointer is nil.
Example (DataCleaning) ¶
package main import ( "encoding/csv" "fmt" "io" "strings" "github.com/askeladdk/csvbuddy" ) func main() { // A messy CSV that is missing a header, uses semicolon delimiter, // has numbers with comma decimals, inconsistent capitalization, and stray spaces. var messyCSV = strings.Join([]string{ "Tokyo ; JP ; 35,6897 ; 139,6922", "jakarta ; Id ; -6,2146 ; 106,8451", "DELHI ; in ; 28,6600 ; 77,2300 ", }, "\n") type city struct { Name string `csv:"name"` Country string `csv:"country"` Latitude float32 `csv:"lat"` Longitude float32 `csv:"lng"` } d := csvbuddy.NewDecoder(strings.NewReader(messyCSV)) // Set the Decoder to use the header derived from the city struct fields. d.SkipHeader() // Set the CSV reader to delimit on semicolons. d.SetReaderFunc(func(r io.Reader) csvbuddy.Reader { cr := csv.NewReader(r) cr.Comma = ';' cr.ReuseRecord = true return cr }) // Set the Decoder to clean messy values. d.SetMapFunc(func(name, value string) string { value = strings.TrimSpace(value) switch name { case "lat", "lng": value = strings.ReplaceAll(value, ",", ".") case "name": value = strings.Title(strings.ToLower(value)) //nolint case "country": value = strings.ToUpper(value) } return value }) // Decode into the cities variable. var cities []city _ = d.Decode(&cities) for _, city := range cities { fmt.Printf("%s, %s is located at coordinate (%.4f, %.4f).\n", city.Name, city.Country, city.Latitude, city.Longitude) } }
Output: Tokyo, JP is located at coordinate (35.6897, 139.6922). Jakarta, ID is located at coordinate (-6.2146, 106.8451). Delhi, IN is located at coordinate (28.6600, 77.2300).
Example (DecoderIterate) ¶
package main import ( "fmt" "strings" "github.com/askeladdk/csvbuddy" ) func main() { moviesCSV := strings.Join([]string{ "movie,year of release", "The Matrix,1999", "Back To The Future,1985", "The Terminator,1984", "2001: A Space Odyssey,1968", }, "\n") var movie struct { Name string `csv:"movie"` Year int `csv:"year of release"` } cr := csvbuddy.NewDecoder(strings.NewReader(moviesCSV)) iter, _ := cr.Iterate(&movie) for iter.Scan() { fmt.Printf("%s was released in %d.\n", movie.Name, movie.Year) } }
Output: The Matrix was released in 1999. Back To The Future was released in 1985. The Terminator was released in 1984. 2001: A Space Odyssey was released in 1968.
Example (FloatingPointTags) ¶
package main import ( "fmt" "math" "github.com/askeladdk/csvbuddy" ) func main() { numbers := []struct { N float64 `csv:"number,prec=3,fmt=E"` }{{math.Pi}, {100e4}} text, _ := csvbuddy.Marshal(&numbers) fmt.Println(string(text)) }
Output: number 3.142E+00 1.000E+06
Example (Marshal) ¶
package main import ( "fmt" "github.com/askeladdk/csvbuddy" ) func main() { movies := []struct { Name string `csv:"movie"` Year int `csv:"year of release"` }{ {"The Matrix", 1999}, {"Back To The Future", 1985}, {"The Terminator", 1984}, {"2001: A Space Odyssey", 1968}, } text, _ := csvbuddy.Marshal(&movies) fmt.Println(string(text)) }
Output: movie,year of release The Matrix,1999 Back To The Future,1985 The Terminator,1984 2001: A Space Odyssey,1968
Example (Unmarshal) ¶
package main import ( "fmt" "strings" "github.com/askeladdk/csvbuddy" ) func main() { moviesCSV := strings.Join([]string{ "movie,year of release", "The Matrix,1999", "Back To The Future,1985", "The Terminator,1984", "2001: A Space Odyssey,1968", }, "\n") var movies []struct { Name string `csv:"movie"` Year int `csv:"year of release"` } _ = csvbuddy.Unmarshal([]byte(moviesCSV), &movies) for _, movie := range movies { fmt.Printf("%s was released in %d.\n", movie.Name, movie.Year) } }
Output: The Matrix was released in 1999. Back To The Future was released in 1985. The Terminator was released in 1984. 2001: A Space Odyssey was released in 1968.
Index ¶
- Variables
- func Header(v interface{}) ([]string, error)
- func Marshal(v interface{}) ([]byte, error)
- func Unmarshal(data []byte, v interface{}) error
- type Decoder
- func (d *Decoder) Decode(v interface{}) error
- func (d *Decoder) DisallowShortFields()
- func (d *Decoder) DisallowUnknownFields()
- func (d *Decoder) Iterate(v interface{}) (*DecoderIterator, error)
- func (d *Decoder) SetMapFunc(fn MapFunc)
- func (d *Decoder) SetReaderFunc(fn ReaderFunc)
- func (d *Decoder) SkipHeader()
- type DecoderIterator
- type Encoder
- type MapFunc
- type Reader
- type ReaderFunc
- type Writer
- type WriterFunc
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrInvalidArgument = errors.New("csv: interface{} argument is of an invalid type")
ErrInvalidArgument signals that an interface{} argument is of an invalid type.
Functions ¶
func Header ¶ added in v0.0.2
Header returns the header of v, which must be a pointer to a slice of structs.
Types ¶
type Decoder ¶
type Decoder struct {
// contains filtered or unexported fields
}
Decoder reads and decodes CSV records from an input stream.
func NewDecoder ¶
NewDecoder returns a Decoder that reads from r.
func (*Decoder) Decode ¶
Decode decodes a CSV as a slice of structs and stores it in v. The value of v must be a pointer to a slice of structs.
func (*Decoder) DisallowShortFields ¶ added in v0.0.3
func (d *Decoder) DisallowShortFields()
DisallowShortFields causes the Decoder to raise an error if a record has fewer columns than struct fields.
func (*Decoder) DisallowUnknownFields ¶
func (d *Decoder) DisallowUnknownFields()
DisallowUnknownFields causes the Decoder to raise an error if a record has more columns than struct fields.
func (*Decoder) Iterate ¶ added in v0.0.5
func (d *Decoder) Iterate(v interface{}) (*DecoderIterator, error)
Iterate returns a DecoderIterator that decodes each row into v, which must be a pointer to a struct.
func (*Decoder) SetMapFunc ¶
SetMapFunc causes the Decoder to call fn on every field before type conversion. Use this to clean wrongly formatted values.
func (*Decoder) SetReaderFunc ¶
func (d *Decoder) SetReaderFunc(fn ReaderFunc)
SetReaderFunc customizes how records are decoded. The default value is NewReader.
func (*Decoder) SkipHeader ¶
func (d *Decoder) SkipHeader()
SkipHeader causes the Decoder to not parse the first record as the header but to derive it from the struct tags. Use this to read headerless CSVs.
type DecoderIterator ¶ added in v0.0.5
type DecoderIterator struct {
// contains filtered or unexported fields
}
DecoderIterator decodes one row at a time to enable parsing of large files without having to read them entirely into memory.
func (*DecoderIterator) Err ¶ added in v0.0.5
func (d *DecoderIterator) Err() error
Err returns the most recent non-EOF error.
func (*DecoderIterator) Scan ¶ added in v0.0.5
func (d *DecoderIterator) Scan() bool
Scan parses the next row and stores the result in the value passed into Decoder.Iterate. It returns false when an error has occurred or it reached EOF. After Scan returns false, Err will return the error that caused it to stop. If Scan stopped because it has reached EOF, Err will return nil.
type Encoder ¶
type Encoder struct {
// contains filtered or unexported fields
}
Encoder writes and encodes CSV records to an output stream.
func (*Encoder) Encode ¶
Encode encodes a slice of structs to CSV text format. The value of v must be a pointer to a slice of structs.
func (*Encoder) SetHeader ¶ added in v0.0.2
SetHeader causes the Encoder to change the order in which fields are encoded.
func (*Encoder) SetMapFunc ¶
SetMapFunc causes the Encoder to call fn on every field before a record is written.
func (*Encoder) SetWriterFunc ¶
func (e *Encoder) SetWriterFunc(fn WriterFunc)
SetWriterFunc customizes how records are encoded. The default value is NewWriter.
func (*Encoder) SkipHeader ¶
func (e *Encoder) SkipHeader()
SkipHeader causes the Encoder to not write the CSV header.
type Reader ¶
Reader parses a CSV input stream to records. A Reader must return io.EOF to signal end of file.
type ReaderFunc ¶
ReaderFunc is a function that returns a Reader that reads from an input stream.
type Writer ¶
Writer writes CSV records.
Writer may optionally support flushing by implementing Flush() error.
type WriterFunc ¶
WriterFunc is a function that returns a Writer that writes to an output stream.