pkg.re/essentialkaos/ek.10@v12.41.0+incompatible/csv/csv.go (about) 1 // Package csv contains simple CSV parser 2 package csv 3 4 // ////////////////////////////////////////////////////////////////////////////////// // 5 // // 6 // Copyright (c) 2022 ESSENTIAL KAOS // 7 // Apache License, Version 2.0 <https://www.apache.org/licenses/LICENSE-2.0> // 8 // // 9 // ////////////////////////////////////////////////////////////////////////////////// // 10 11 import ( 12 "bufio" 13 "errors" 14 "io" 15 "strings" 16 ) 17 18 // ////////////////////////////////////////////////////////////////////////////////// // 19 20 // Reader is reader struct 21 type Reader struct { 22 Comma rune 23 br *bufio.Reader 24 } 25 26 // ////////////////////////////////////////////////////////////////////////////////// // 27 28 // ErrEmptyDest is returned by the ReadTo method if empty destintation slice was given 29 var ErrEmptyDest = errors.New("Destination slice length must be greater than 1") 30 31 // ////////////////////////////////////////////////////////////////////////////////// // 32 33 // NewReader create new CSV reader 34 func NewReader(r io.Reader) *Reader { 35 return &Reader{ 36 Comma: ';', 37 br: bufio.NewReader(r), 38 } 39 } 40 41 // ////////////////////////////////////////////////////////////////////////////////// // 42 43 // Read reads line from CSV file 44 func (r *Reader) Read() ([]string, error) { 45 str, _, err := r.br.ReadLine() 46 47 if err != nil || len(str) == 0 { 48 return nil, err 49 } 50 51 return strings.Split(string(str), string(r.Comma)), nil 52 } 53 54 // ReadTo reads data to given slice 55 func (r *Reader) ReadTo(dst []string) error { 56 if len(dst) == 0 { 57 return ErrEmptyDest 58 } 59 60 str, _, err := r.br.ReadLine() 61 62 if err != nil { 63 return err 64 } 65 66 parseAndFill(string(str), dst, string(r.Comma)) 67 68 return nil 69 } 70 71 // ////////////////////////////////////////////////////////////////////////////////// // 72 73 func parseAndFill(src string, dst []string, sep string) { 74 l := len(dst) 75 76 if src == "" { 77 clean(dst, 0, l) 78 return 79 } 80 81 n := strings.Count(src, sep) 82 i := 0 83 84 if n == 0 { 85 dst[0] = src 86 clean(dst, 1, l) 87 return 88 } 89 90 for i < n && i < l { 91 m := strings.Index(src, sep) 92 93 dst[i] = src[:m] 94 src = src[m+1:] 95 96 i++ 97 } 98 99 if src != "" && i != l { 100 dst[i] = src 101 } 102 103 if i < l-1 { 104 clean(dst, i, l) 105 } 106 } 107 108 func clean(dst []string, since, to int) { 109 for i := since; i < to; i++ { 110 dst[i] = "" 111 } 112 }