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  }