csv support

master
Starainrt 3 years ago
parent c3ca057b96
commit fd5cf2c1f6

@ -18,4 +18,4 @@ func GetFileCreationTime(fileinfo os.FileInfo) time.Time {
func GetFileAccessTime(fileinfo os.FileInfo) time.Time {
return timespecToTime(fileinfo.Sys().(*syscall.Stat_t).Atim)
}
}

@ -17,3 +17,11 @@ func GetFileAccessTime(fileinfo os.FileInfo) time.Time {
d := fileinfo.Sys().(*syscall.Win32FileAttributeData)
return time.Unix(0, d.LastAccessTime.Nanoseconds())
}
func SetFileTimes(file *os.File,info os.FileInfo) {
}
func SetFileTimesbyTime(file *os.File) {
syscall.SetFileTime()
}

@ -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
}

@ -482,7 +482,7 @@ func SliceIn(slice interface{}, data interface{}) bool {
// Unmarshal 输出结果到结构体中
func (cfg *SysConf) Unmarshal(ins interface{}) error {
var structSet func(t reflect.Type, v reflect.Value) error
var structSet func(t reflect.Type, v reflect.Value,oriSeg string) error
t := reflect.TypeOf(ins)
v := reflect.ValueOf(ins).Elem()
if v.Kind() != reflect.Struct {
@ -492,7 +492,7 @@ func (cfg *SysConf) Unmarshal(ins interface{}) error {
return errors.New("Cannot Write!")
}
t = t.Elem()
structSet = func(t reflect.Type, v reflect.Value) error {
structSet = func(t reflect.Type, v reflect.Value,oriSeg string) error {
for i := 0; i < t.NumField(); i++ {
tp := t.Field(i)
vl := v.Field(i)
@ -500,11 +500,14 @@ func (cfg *SysConf) Unmarshal(ins interface{}) error {
continue
}
if vl.Type().Kind() == reflect.Struct {
structSet(vl.Type(), vl)
structSet(vl.Type(), vl,tp.Tag.Get("seg"))
continue
}
seg := tp.Tag.Get("seg")
key := tp.Tag.Get("key")
if oriSeg!="" {
seg=oriSeg
}
if seg == "" || key == "" {
continue
}
@ -532,12 +535,12 @@ func (cfg *SysConf) Unmarshal(ins interface{}) error {
}
return nil
}
return structSet(t, v)
return structSet(t, v,"")
}
// Marshal 输出结果到结构体中
func (cfg *SysConf) Marshal(ins interface{}) ([]byte, error) {
var structSet func(t reflect.Type, v reflect.Value)
var structSet func(t reflect.Type, v reflect.Value,oriSeg string)
t := reflect.TypeOf(ins)
v := reflect.ValueOf(ins)
if v.Kind() != reflect.Struct {
@ -547,18 +550,21 @@ func (cfg *SysConf) Marshal(ins interface{}) ([]byte, error) {
t = t.Elem()
v = v.Elem()
}
structSet = func(t reflect.Type, v reflect.Value) {
structSet = func(t reflect.Type, v reflect.Value,oriSeg string) {
for i := 0; i < t.NumField(); i++ {
var seg, key, comment string = "", "", ""
tp := t.Field(i)
vl := v.Field(i)
if vl.Type().Kind() == reflect.Struct {
structSet(vl.Type(), vl)
structSet(vl.Type(), vl,tp.Tag.Get("seg"))
continue
}
seg = tp.Tag.Get("seg")
key = tp.Tag.Get("key")
comment = tp.Tag.Get("comment")
if oriSeg != "" {
seg=oriSeg
}
if seg == "" || key == "" {
continue
}
@ -569,7 +575,7 @@ func (cfg *SysConf) Marshal(ins interface{}) ([]byte, error) {
}
}
structSet(t, v)
structSet(t, v,"")
return cfg.Build(), nil
}

@ -36,3 +36,33 @@ func Test_Parse(t *testing.T) {
//fmt.Println(cfg.Data[0].Comment)
fmt.Println(string(cfg.Build()))
}
type slicetest struct {
A string `seg:"s" key:"a"`
B string `seg:"a" key:"b"`
}
type testme struct {
Love slicetest `seg:"love"`
Star slicetest `seg:"star"`
}
func Test_Marshal(t *testing.T) {
var info string =`
[love]
a=abc
b=123
[star]
a=456
b=789
`
var tmp testme
ini:=NewIni()
ini.Parse([]byte(info))
ini.Unmarshal(&tmp)
fmt.Printf("%+v\n",tmp)
b,_:=ini.Marshal(tmp)
fmt.Println(string(b))
}
Loading…
Cancel
Save