mirror of
https://gitee.com/johng/gf
synced 2026-06-06 16:21:40 +08:00
add package gini
This commit is contained in:
113
encoding/gini/gini.go
Normal file
113
encoding/gini/gini.go
Normal file
@ -0,0 +1,113 @@
|
||||
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package gini provides accessing and converting for INI content.
|
||||
package gini
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//Decode converts INI format to map
|
||||
func Decode(data []byte) (res map[string]interface{}, err error) {
|
||||
res = make(map[string]interface{})
|
||||
fieldMap := make(map[string]interface{})
|
||||
|
||||
a := bytes.NewReader(data)
|
||||
|
||||
r := bufio.NewReader(a)
|
||||
|
||||
var section string
|
||||
var lastSection string
|
||||
var haveSection bool
|
||||
for {
|
||||
line, err := r.ReadString('\n')
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lineStr := strings.TrimSpace(string(line))
|
||||
if len(lineStr) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if lineStr[0] == ';' || lineStr[0] == '#' {
|
||||
continue
|
||||
}
|
||||
|
||||
sectionBeginPos := strings.Index(lineStr, "[")
|
||||
sectionEndPos := strings.Index(lineStr, "]")
|
||||
|
||||
if sectionBeginPos >= 0 && sectionEndPos >= 2 {
|
||||
section = lineStr[sectionBeginPos+1 : sectionEndPos]
|
||||
|
||||
if lastSection == "" {
|
||||
lastSection = section
|
||||
} else if lastSection != section {
|
||||
lastSection = section
|
||||
fieldMap = make(map[string]interface{})
|
||||
}
|
||||
haveSection = true
|
||||
} else if haveSection == false {
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.Contains(lineStr, "=") && haveSection {
|
||||
values := strings.Split(lineStr, "=")
|
||||
|
||||
fieldMap[strings.TrimSpace(values[0])] = strings.TrimSpace(strings.Join(values[1:], ""))
|
||||
res[section] = fieldMap
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
//Encode converts map to INI format
|
||||
func Encode(data map[string]interface{}) (res []byte, err error) {
|
||||
w := new(bytes.Buffer)
|
||||
|
||||
w.WriteString(";gini\n")
|
||||
for k, v := range data {
|
||||
n, err := w.WriteString(fmt.Sprintf("[%s]\n", k))
|
||||
if err != nil || n == 0 {
|
||||
return nil, fmt.Errorf("write data failed. %v", err)
|
||||
}
|
||||
|
||||
for kk, vv := range v.(map[string]interface{}) {
|
||||
n, err := w.WriteString(fmt.Sprintf("%s=%s\n", kk, vv.(string)))
|
||||
if err != nil || n == 0 {
|
||||
return nil, fmt.Errorf("write data failed. %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
res = make([]byte, w.Len())
|
||||
n, err := w.Read(res)
|
||||
if err != nil || n == 0 {
|
||||
return nil, fmt.Errorf("write data failed. %v", err)
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
//ToJson convert INI format to JSON
|
||||
func ToJson(data []byte) (res []byte, err error) {
|
||||
iniMap, err := Decode(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return json.Marshal(iniMap)
|
||||
}
|
||||
97
encoding/gini/gini_test.go
Normal file
97
encoding/gini/gini_test.go
Normal file
@ -0,0 +1,97 @@
|
||||
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gini_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/encoding/gini"
|
||||
"github.com/gogf/gf/encoding/gjson"
|
||||
"github.com/gogf/gf/test/gtest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var iniContent = `
|
||||
|
||||
;注释
|
||||
aa=bb
|
||||
[addr]
|
||||
#注释
|
||||
ip = 127.0.0.1
|
||||
port=9001
|
||||
enable=true
|
||||
|
||||
[DBINFO]
|
||||
type=mysql
|
||||
user=root
|
||||
password=password
|
||||
[键]
|
||||
呵呵=值
|
||||
|
||||
`
|
||||
|
||||
func TestDecode(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
res, err := gini.Decode([]byte(iniContent))
|
||||
if err != nil {
|
||||
gtest.Fatal(err)
|
||||
}
|
||||
fmt.Println(res)
|
||||
gtest.Assert(res["addr"].(map[string]interface{})["ip"], "127.0.0.1")
|
||||
gtest.Assert(res["addr"].(map[string]interface{})["port"], "9001")
|
||||
gtest.Assert(res["DBINFO"].(map[string]interface{})["user"], "root")
|
||||
gtest.Assert(res["DBINFO"].(map[string]interface{})["type"], "mysql")
|
||||
gtest.Assert(res["键"].(map[string]interface{})["呵呵"], "值")
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestEncode(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
iniMap, err := gini.Decode([]byte(iniContent))
|
||||
if err != nil {
|
||||
gtest.Fatal(err)
|
||||
}
|
||||
|
||||
iniStr, err := gini.Encode(iniMap)
|
||||
if err != nil {
|
||||
gtest.Fatal(err)
|
||||
}
|
||||
|
||||
res, err := gini.Decode(iniStr)
|
||||
if err != nil {
|
||||
gtest.Fatal(err)
|
||||
}
|
||||
|
||||
gtest.Assert(res["addr"].(map[string]interface{})["ip"], "127.0.0.1")
|
||||
gtest.Assert(res["addr"].(map[string]interface{})["port"], "9001")
|
||||
gtest.Assert(res["DBINFO"].(map[string]interface{})["user"], "root")
|
||||
gtest.Assert(res["DBINFO"].(map[string]interface{})["type"], "mysql")
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestToJson(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
jsonStr, err := gini.ToJson([]byte(iniContent))
|
||||
if err != nil {
|
||||
gtest.Fatal(err)
|
||||
}
|
||||
|
||||
json, err := gjson.LoadContent(jsonStr)
|
||||
if err != nil {
|
||||
gtest.Fatal(err)
|
||||
}
|
||||
|
||||
iniMap, err := gini.Decode([]byte(iniContent))
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
gtest.Assert(iniMap["addr"].(map[string]interface{})["ip"], json.GetString("addr.ip"))
|
||||
gtest.Assert(iniMap["addr"].(map[string]interface{})["port"], json.GetString("addr.port"))
|
||||
gtest.Assert(iniMap["DBINFO"].(map[string]interface{})["user"], json.GetString("DBINFO.user"))
|
||||
gtest.Assert(iniMap["DBINFO"].(map[string]interface{})["type"], json.GetString("DBINFO.type"))
|
||||
})
|
||||
}
|
||||
@ -8,7 +8,7 @@ package gjson
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/gogf/gf/encoding/gini"
|
||||
"github.com/gogf/gf/encoding/gtoml"
|
||||
"github.com/gogf/gf/encoding/gxml"
|
||||
"github.com/gogf/gf/encoding/gyaml"
|
||||
@ -75,3 +75,14 @@ func (j *Json) ToTomlString() (string, error) {
|
||||
b, e := j.ToToml()
|
||||
return string(b), e
|
||||
}
|
||||
|
||||
func (j *Json) ToIni() ([]byte, error) {
|
||||
j.mu.RLock()
|
||||
defer j.mu.RUnlock()
|
||||
return gini.Encode((*(j.p)).(map[string]interface{}))
|
||||
}
|
||||
|
||||
func (j *Json) ToIniString() (string, error) {
|
||||
b, e := j.ToToml()
|
||||
return string(b), e
|
||||
}
|
||||
|
||||
@ -12,17 +12,16 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/gogf/gf/os/gfile"
|
||||
|
||||
"github.com/gogf/gf/encoding/gini"
|
||||
"github.com/gogf/gf/encoding/gtoml"
|
||||
"github.com/gogf/gf/encoding/gxml"
|
||||
"github.com/gogf/gf/encoding/gyaml"
|
||||
"github.com/gogf/gf/internal/rwmutex"
|
||||
"github.com/gogf/gf/os/gfcache"
|
||||
"github.com/gogf/gf/os/gfile"
|
||||
"github.com/gogf/gf/text/gregex"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// New creates a Json object with any variable type of <data>,
|
||||
@ -147,6 +146,10 @@ func LoadToml(data interface{}, safe ...bool) (*Json, error) {
|
||||
return doLoadContent("toml", gconv.Bytes(data), safe...)
|
||||
}
|
||||
|
||||
func LoadIni(data interface{}, safe ...bool) (*Json, error) {
|
||||
return doLoadContent("ini", gconv.Bytes(data), safe...)
|
||||
}
|
||||
|
||||
func doLoadContent(dataType string, data []byte, safe ...bool) (*Json, error) {
|
||||
var err error
|
||||
var result interface{}
|
||||
@ -173,7 +176,10 @@ func doLoadContent(dataType string, data []byte, safe ...bool) (*Json, error) {
|
||||
if data, err = gtoml.ToJson(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
case "ini", ".ini":
|
||||
if data, err = gini.ToJson(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
err = errors.New("unsupported type for loading")
|
||||
}
|
||||
@ -211,6 +217,8 @@ func checkDataType(content []byte) string {
|
||||
return "xml"
|
||||
} else if gregex.IsMatch(`^[\s\t]*[\w\-]+\s*:\s*.+`, content) || gregex.IsMatch(`\n[\s\t]*[\w\-]+\s*:\s*.+`, content) {
|
||||
return "yml"
|
||||
} else if (gregex.IsMatch(`^[\s\t\[*\]].?*[\w\-]+\s*=\s*.+`, content) || gregex.IsMatch(`\n[\s\t\[*\]]*[\w\-]+\s*=\s*.+`, content)) && gregex.IsMatch(`\n[\s\t]*[\w\-]+\s*=*\"*.+\"`, content) == false && gregex.IsMatch(`^[\s\t]*[\w\-]+\s*=*\"*.+\"`, content) == false {
|
||||
return "ini"
|
||||
} else if gregex.IsMatch(`^[\s\t]*[\w\-]+\s*=\s*.+`, content) || gregex.IsMatch(`\n[\s\t]*[\w\-]+\s*=\s*.+`, content) {
|
||||
return "toml"
|
||||
} else {
|
||||
|
||||
@ -196,3 +196,41 @@ func Test_Load_Basic(t *testing.T) {
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Load_Ini(t *testing.T) {
|
||||
var data = `
|
||||
|
||||
;注释
|
||||
|
||||
[addr]
|
||||
#注释
|
||||
ip = 127.0.0.1
|
||||
port=9001
|
||||
enable=true
|
||||
|
||||
[DBINFO]
|
||||
type=mysql
|
||||
user=root
|
||||
password=password
|
||||
|
||||
`
|
||||
|
||||
gtest.Case(t, func() {
|
||||
json, err := gjson.LoadContent(data)
|
||||
if err != nil {
|
||||
gtest.Fatal(err)
|
||||
}
|
||||
|
||||
gtest.Assert(json.GetString("addr.ip"), "127.0.0.1")
|
||||
gtest.Assert(json.GetString("addr.port"), "9001")
|
||||
gtest.Assert(json.GetString("addr.enable"), "true")
|
||||
gtest.Assert(json.GetString("DBINFO.type"), "mysql")
|
||||
gtest.Assert(json.GetString("DBINFO.user"), "root")
|
||||
gtest.Assert(json.GetString("DBINFO.password"), "password")
|
||||
|
||||
_, err = json.ToIni()
|
||||
if err != nil {
|
||||
gtest.Fatal(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -37,3 +37,7 @@ func VarToYaml(value interface{}) ([]byte, error) {
|
||||
func VarToToml(value interface{}) ([]byte, error) {
|
||||
return New(value).ToToml()
|
||||
}
|
||||
|
||||
func VarToIni(value interface{}) ([]byte, error) {
|
||||
return New(value).ToIni()
|
||||
}
|
||||
|
||||
@ -47,3 +47,7 @@ func LoadYaml(data interface{}, safe ...bool) (*Parser, error) {
|
||||
func LoadToml(data interface{}, safe ...bool) (*Parser, error) {
|
||||
return gjson.LoadToml(data, safe...)
|
||||
}
|
||||
|
||||
func LoadIni(data interface{}, safe ...bool) (*Parser, error) {
|
||||
return gjson.LoadIni(data, safe...)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user