csv support
parent
c3ca057b96
commit
fd5cf2c1f6
@ -0,0 +1,261 @@
|
||||
package sysconf
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
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) (csv CSV, err error) {
|
||||
strData := strings.Split(string(bytes.TrimSpace(data)), "\n")
|
||||
if len(strData) < 1 {
|
||||
err = fmt.Errorf("cannot parse data,invalid data format")
|
||||
}
|
||||
var header []string
|
||||
var text [][]string
|
||||
if hasHeader {
|
||||
header = csvAnalyse(strData[0])
|
||||
strData = strData[1:]
|
||||
} else {
|
||||
num := len(csvAnalyse(strData[0]))
|
||||
for i := 0; i < num; i++ {
|
||||
header = append(header, strconv.Itoa(i))
|
||||
}
|
||||
}
|
||||
for k, v := range strData {
|
||||
tmpData := csvAnalyse(v)
|
||||
if len(tmpData) != len(header) {
|
||||
err = fmt.Errorf("cannot parse data line %d,got %d values but need %d", k, len(tmpData), len(header))
|
||||
return
|
||||
}
|
||||
text = append(text, tmpData)
|
||||
}
|
||||
csv.header = header
|
||||
csv.text = text
|
||||
return
|
||||
}
|
||||
|
||||
func (csv *CSV) Header() []string {
|
||||
return csv.header
|
||||
}
|
||||
|
||||
func (csv *CSV) Data() [][]string {
|
||||
return csv.text
|
||||
}
|
||||
|
||||
func (csv *CSV) Row(row int) *CSVRow {
|
||||
if row >= len(csv.Data()) {
|
||||
return nil
|
||||
}
|
||||
return &CSVRow{
|
||||
header: csv.Header(),
|
||||
data: csv.Data()[row],
|
||||
}
|
||||
}
|
||||
|
||||
func (csv *CSVRow) Get(key string) *CSVValue {
|
||||
for k, v := range csv.header {
|
||||
if v == key {
|
||||
return &CSVValue{
|
||||
key: key,
|
||||
value: csv.data[k],
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (csv *CSVRow) Col(key int) *CSVValue {
|
||||
if key >= len(csv.header) {
|
||||
return nil
|
||||
}
|
||||
return &CSVValue{
|
||||
key: csv.header[key],
|
||||
value: csv.data[key],
|
||||
}
|
||||
}
|
||||
|
||||
func (csv *CSVRow) Header() []string {
|
||||
return csv.header
|
||||
}
|
||||
|
||||
func (csv *CSV) MapData() []map[string]string {
|
||||
var result []map[string]string
|
||||
for _, v := range csv.text {
|
||||
tmp := make(map[string]string)
|
||||
for k, v2 := range csv.header {
|
||||
tmp[v2] = v[k]
|
||||
}
|
||||
result = append(result, tmp)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func CsvAnalyse(data string) []string {
|
||||
return csvAnalyse(data)
|
||||
}
|
||||
|
||||
func csvAnalyse(data string) []string {
|
||||
var segStart bool = false
|
||||
var segReady bool = false
|
||||
var segSign string = ""
|
||||
var dotReady bool = false
|
||||
data = strings.TrimSpace(data)
|
||||
var result []string
|
||||
var seg string
|
||||
for k, v := range []rune(data) {
|
||||
if k == 0 && v != []rune(`"`)[0] {
|
||||
dotReady = true
|
||||
}
|
||||
if v != []rune(`,`)[0] && dotReady {
|
||||
segSign = `,`
|
||||
segStart = true
|
||||
dotReady = false
|
||||
if v == []rune(`"`)[0] {
|
||||
segSign = `"`
|
||||
continue
|
||||
}
|
||||
}
|
||||
if dotReady && v == []rune(`,`)[0] {
|
||||
//dotReady = false
|
||||
result = append(result, "")
|
||||
continue
|
||||
}
|
||||
|
||||
if v == []rune(`"`)[0] && segStart {
|
||||
if !segReady {
|
||||
segReady = true
|
||||
continue
|
||||
}
|
||||
seg += `"`
|
||||
segReady = false
|
||||
continue
|
||||
}
|
||||
if segReady && segSign == `"` && segStart {
|
||||
segReady = false
|
||||
segStart = false
|
||||
result = append(result, seg)
|
||||
segSign = ``
|
||||
seg = ""
|
||||
}
|
||||
|
||||
if v == []rune(`"`)[0] && !segStart {
|
||||
segStart = true
|
||||
segReady = false
|
||||
segSign = `"`
|
||||
continue
|
||||
}
|
||||
if v == []rune(`,`)[0] && !segStart {
|
||||
dotReady = true
|
||||
}
|
||||
if v == []rune(`,`)[0] && segStart && segSign == "," {
|
||||
segStart = false
|
||||
result = append(result, seg)
|
||||
dotReady = true
|
||||
segSign = ``
|
||||
seg = ""
|
||||
}
|
||||
if segStart {
|
||||
seg = string(append([]rune(seg), v))
|
||||
}
|
||||
}
|
||||
if len(data) != 0 && len(result) == 0 && seg == "" {
|
||||
result = append(result, data)
|
||||
} else {
|
||||
result = append(result, seg)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func MarshalCSV(header []string, ins interface{}) ([]byte, error) {
|
||||
var result [][]string
|
||||
t := reflect.TypeOf(ins)
|
||||
v := reflect.ValueOf(ins)
|
||||
if v.Kind() != reflect.Slice && v.Kind() != reflect.Array {
|
||||
return nil, errors.New("not a Slice or Array")
|
||||
}
|
||||
if t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
v = v.Elem()
|
||||
}
|
||||
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
subT := reflect.TypeOf(v.Index(i).Interface())
|
||||
subV := reflect.ValueOf(v.Index(i).Interface())
|
||||
if subV.Kind() == reflect.Slice || subV.Kind() == reflect.Array {
|
||||
if subT.Kind() == reflect.Ptr {
|
||||
subV = subV.Elem()
|
||||
}
|
||||
var tmp []string
|
||||
for j := 0; j < subV.Len(); j++ {
|
||||
tmp = append(tmp, fmt.Sprint(reflect.ValueOf(subV.Index(j))))
|
||||
}
|
||||
result = append(result, tmp)
|
||||
}
|
||||
if subV.Kind() == reflect.Struct {
|
||||
var tmp []string
|
||||
if subT.Kind() == reflect.Ptr {
|
||||
subV = subV.Elem()
|
||||
}
|
||||
for i := 0; i < subV.NumField(); i++ {
|
||||
tmp = append(tmp, fmt.Sprint(subV.Field(i)))
|
||||
}
|
||||
result = append(result, tmp)
|
||||
}
|
||||
}
|
||||
|
||||
return buildCSV(header,result)
|
||||
}
|
||||
|
||||
func buildCSV(header []string, data [][]string) ([]byte, error) {
|
||||
var result []string
|
||||
var length int
|
||||
build := func(slc []string) string {
|
||||
for k, v := range slc {
|
||||
if strings.Index(v, `"`) >= 0 {
|
||||
v = strings.ReplaceAll(v, `"`, `""`)
|
||||
}
|
||||
if strings.Index(v,"\n")>=0 {
|
||||
v=strings.ReplaceAll(v,"\n",`\n`)
|
||||
}
|
||||
if strings.Index(v,"\r")>=0 {
|
||||
v=strings.ReplaceAll(v,"\r",`\r`)
|
||||
}
|
||||
v = `"` + v + `"`
|
||||
slc[k] = v
|
||||
}
|
||||
return strings.Join(slc, ",")
|
||||
}
|
||||
if len(header) != 0 {
|
||||
result = append(result, build(header))
|
||||
length = len(header)
|
||||
} else {
|
||||
length = len(data[0])
|
||||
}
|
||||
for k, v := range data {
|
||||
if len(v) != length {
|
||||
return nil, fmt.Errorf("line %d got length %d ,but need %d", k, len(v), length)
|
||||
}
|
||||
result = append(result, build(v))
|
||||
}
|
||||
return []byte(strings.Join(result, "\n")), nil
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package sysconf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_csv(t *testing.T) {
|
||||
//var test Sqlplus
|
||||
var text=`
|
||||
姓名,班级,性别,年龄
|
||||
张三,"我,不""知道",boy,23
|
||||
"里斯","哈哈",girl,23
|
||||
`
|
||||
fmt.Println(csvAnalyse(`请求权,lkjdshck,dsvdsv,"sdvkjsdv,",=dsvdsv,"=,dsvsdv"`))
|
||||
a,b:=ParseCSV([]byte(text),true)
|
||||
fmt.Println(b)
|
||||
fmt.Println(a.Row(0).Col(3).MustInt())
|
||||
}
|
||||
|
||||
type csvtest struct {
|
||||
A string
|
||||
B int
|
||||
}
|
||||
func Test_Masharl(t *testing.T) {
|
||||
//var test Sqlplus
|
||||
/*
|
||||
var a []csvtest = []csvtest{
|
||||
{"lala",1},
|
||||
{"haha",34},
|
||||
}
|
||||
*/
|
||||
var a [][]string
|
||||
a=append(a,[]string{"a","b","c"})
|
||||
a=append(a,[]string{"1",`s"s"d`,"3"})
|
||||
b,_:=MarshalCSV([]string{},a)
|
||||
fmt.Println(string(b))
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
package sysconf
|
||||
|
||||
import "strconv"
|
||||
|
||||
func (csv *CSVValue)Key()string {
|
||||
return csv.key
|
||||
}
|
||||
|
||||
func (csv *CSVValue)Int()(int,error) {
|
||||
tmp,err:=strconv.Atoi(csv.value)
|
||||
return tmp,err
|
||||
}
|
||||
|
||||
func (csv *CSVValue)MustInt()int {
|
||||
tmp,err:=csv.Int()
|
||||
if err!=nil {
|
||||
panic(err)
|
||||
}
|
||||
return tmp
|
||||
}
|
||||
|
||||
func (csv *CSVValue)Int64()(int64,error) {
|
||||
tmp,err:=strconv.ParseInt(csv.value,10,64)
|
||||
return tmp,err
|
||||
}
|
||||
|
||||
func (csv *CSVValue)MustInt64()int64 {
|
||||
tmp,err:=csv.Int64()
|
||||
if err!=nil {
|
||||
panic(err)
|
||||
}
|
||||
return tmp
|
||||
}
|
||||
|
||||
func (csv *CSVValue)Int32()(int32,error) {
|
||||
tmp,err:=strconv.ParseInt(csv.value,10,32)
|
||||
return int32(tmp),err
|
||||
}
|
||||
|
||||
func (csv *CSVValue)MustInt32()int32 {
|
||||
tmp,err:=csv.Int32()
|
||||
if err!=nil {
|
||||
panic(err)
|
||||
}
|
||||
return tmp
|
||||
}
|
||||
|
||||
func (csv *CSVValue)Uint64()(uint64,error) {
|
||||
tmp,err:=strconv.ParseUint(csv.value,10,64)
|
||||
return tmp,err
|
||||
}
|
||||
|
||||
func (csv *CSVValue)MustUint64()uint64 {
|
||||
tmp,err:=csv.Uint64()
|
||||
if err!=nil {
|
||||
panic(err)
|
||||
}
|
||||
return tmp
|
||||
}
|
||||
|
||||
func (csv *CSVValue)Uint32()(uint32,error) {
|
||||
tmp,err:=strconv.ParseUint(csv.value,10,32)
|
||||
return uint32(tmp),err
|
||||
}
|
||||
|
||||
func (csv *CSVValue)MustUint32()uint32 {
|
||||
tmp,err:=csv.Uint32()
|
||||
if err!=nil {
|
||||
panic(err)
|
||||
}
|
||||
return tmp
|
||||
}
|
||||
|
||||
func (csv *CSVValue)String()string {
|
||||
return csv.value
|
||||
}
|
||||
|
||||
func (csv *CSVValue)Byte()[]byte {
|
||||
return []byte(csv.value)
|
||||
}
|
||||
|
||||
|
||||
func (csv *CSVValue)Bool()(bool,error) {
|
||||
tmp,err:=strconv.ParseBool(csv.value)
|
||||
return tmp,err
|
||||
}
|
||||
|
||||
func (csv *CSVValue)MustBool()bool {
|
||||
tmp,err:=csv.Bool()
|
||||
if err!=nil {
|
||||
panic(err)
|
||||
}
|
||||
return tmp
|
||||
}
|
||||
|
||||
func (csv *CSVValue)Float64()(float64,error) {
|
||||
tmp,err:=strconv.ParseFloat(csv.value,64)
|
||||
return tmp,err
|
||||
}
|
||||
|
||||
func (csv *CSVValue)MustFloat64()float64 {
|
||||
tmp,err:=csv.Float64()
|
||||
if err!=nil {
|
||||
panic(err)
|
||||
}
|
||||
return tmp
|
||||
}
|
||||
|
||||
func (csv *CSVValue)Float32()(float32,error) {
|
||||
tmp,err:=strconv.ParseFloat(csv.value,32)
|
||||
return float32(tmp),err
|
||||
}
|
||||
|
||||
func (csv *CSVValue)MustFloat32()float32 {
|
||||
tmp,err:=csv.Float32()
|
||||
if err!=nil {
|
||||
panic(err)
|
||||
}
|
||||
return tmp
|
||||
}
|
Loading…
Reference in New Issue