staros/sysconf/csv.go

178 lines
4.0 KiB
Go
Raw Permalink Normal View History

2021-05-17 15:09:04 +08:00
package sysconf
import (
"bytes"
"encoding/csv"
2021-05-17 15:09:04 +08:00
"errors"
"fmt"
"reflect"
"strings"
)
var ErrNilCSVValue = errors.New("nil csv value")
2021-05-17 15:09:04 +08:00
type CSV struct {
header []string
text [][]string
}
type CSVRow struct {
header []string
data []string
}
type CSVValue struct {
key string
value string
}
func ParseCSV(data []byte, hasHeader bool) (csvData CSV, err error) {
if len(data) == 0 {
return CSV{}, fmt.Errorf("cannot parse data,invalid data format")
}
reader := csv.NewReader(bytes.NewReader(data))
records, err := reader.ReadAll()
if err != nil {
return CSV{}, err
2021-05-17 15:09:04 +08:00
}
if len(records) == 0 {
return CSV{}, fmt.Errorf("cannot parse data,invalid data format")
}
start := 0
2021-05-17 15:09:04 +08:00
if hasHeader {
csvData.header = append([]string(nil), records[0]...)
start = 1
2021-05-17 15:09:04 +08:00
} else {
for i := range records[0] {
csvData.header = append(csvData.header, fmt.Sprint(i))
2021-05-17 15:09:04 +08:00
}
}
for _, record := range records[start:] {
if len(record) != len(csvData.header) {
return CSV{}, fmt.Errorf("cannot parse data line,got %d values but need %d", len(record), len(csvData.header))
2021-05-17 15:09:04 +08:00
}
csvData.text = append(csvData.text, append([]string(nil), record...))
2021-05-17 15:09:04 +08:00
}
return csvData, nil
2021-05-17 15:09:04 +08:00
}
func (csvData *CSV) Header() []string { return csvData.header }
func (csvData *CSV) Data() [][]string { return csvData.text }
2021-05-17 15:09:04 +08:00
func (csvData *CSV) Row(row int) *CSVRow {
if csvData == nil || row < 0 || row >= len(csvData.text) {
2021-05-17 15:09:04 +08:00
return nil
}
return &CSVRow{header: csvData.header, data: csvData.text[row]}
2021-05-17 15:09:04 +08:00
}
func (row *CSVRow) Get(key string) *CSVValue {
if row == nil {
return nil
}
for idx, header := range row.header {
if header == key {
return &CSVValue{key: key, value: row.data[idx]}
2021-05-17 15:09:04 +08:00
}
}
return nil
}
func (row *CSVRow) Col(key int) *CSVValue {
if row == nil || key < 0 || key >= len(row.header) {
2021-05-17 15:09:04 +08:00
return nil
}
return &CSVValue{key: row.header[key], value: row.data[key]}
2021-05-17 15:09:04 +08:00
}
func (row *CSVRow) Header() []string { return row.header }
2021-05-17 15:09:04 +08:00
func (csvData *CSV) MapData() []map[string]string {
2021-05-17 15:09:04 +08:00
var result []map[string]string
for _, record := range csvData.text {
item := make(map[string]string, len(csvData.header))
for idx, header := range csvData.header {
item[header] = record[idx]
2021-05-17 15:09:04 +08:00
}
result = append(result, item)
2021-05-17 15:09:04 +08:00
}
return result
}
func CsvAnalyse(data string) []string { return csvAnalyse(data) }
2021-05-17 15:09:04 +08:00
func csvAnalyse(data string) []string {
reader := csv.NewReader(strings.NewReader(data))
record, err := reader.Read()
if err != nil {
return []string{}
2021-05-17 15:09:04 +08:00
}
return record
2021-05-17 15:09:04 +08:00
}
func MarshalCSV(header []string, ins interface{}) ([]byte, error) {
v := reflect.ValueOf(ins)
if v.Kind() == reflect.Ptr {
if v.IsNil() {
return nil, ErrNilCSVValue
}
2021-05-17 15:09:04 +08:00
v = v.Elem()
}
if v.Kind() != reflect.Slice && v.Kind() != reflect.Array {
return nil, fmt.Errorf("not a Slice or Array")
}
rows := make([][]string, 0, v.Len())
2021-05-17 15:09:04 +08:00
for i := 0; i < v.Len(); i++ {
item := v.Index(i)
if item.Kind() == reflect.Ptr {
if item.IsNil() {
continue
2021-05-17 15:09:04 +08:00
}
item = item.Elem()
2021-05-17 15:09:04 +08:00
}
switch item.Kind() {
case reflect.Slice, reflect.Array:
row := make([]string, 0, item.Len())
for j := 0; j < item.Len(); j++ {
row = append(row, fmt.Sprint(item.Index(j).Interface()))
2021-05-17 15:09:04 +08:00
}
rows = append(rows, row)
case reflect.Struct:
row := make([]string, 0, item.NumField())
for j := 0; j < item.NumField(); j++ {
field := item.Field(j)
if !field.CanInterface() {
continue
}
row = append(row, fmt.Sprint(field.Interface()))
2021-05-17 15:09:04 +08:00
}
rows = append(rows, row)
2021-05-17 15:09:04 +08:00
}
}
width := 0
if len(header) > 0 {
width = len(header)
} else if len(rows) > 0 {
width = len(rows[0])
}
for idx, row := range rows {
if len(row) != width {
return nil, fmt.Errorf("line %d got length %d ,but need %d", idx, len(row), width)
2021-05-17 15:09:04 +08:00
}
}
var buf bytes.Buffer
writer := csv.NewWriter(&buf)
if len(header) > 0 {
if err := writer.Write(header); err != nil {
return nil, err
}
2021-05-17 15:09:04 +08:00
}
for _, row := range rows {
if err := writer.Write(row); err != nil {
return nil, err
2021-05-17 15:09:04 +08:00
}
}
writer.Flush()
return buf.Bytes(), writer.Error()
2021-05-17 15:09:04 +08:00
}