forked from gookit/goutil
-
Notifications
You must be signed in to change notification settings - Fork 0
/
jsonutil.go
154 lines (132 loc) · 3.13 KB
/
jsonutil.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// Package jsonutil provide some util functions for quick operate JSON data
package jsonutil
import (
"bytes"
"encoding/json"
"os"
"regexp"
"strings"
"text/scanner"
)
// WriteFile write data to JSON file
func WriteFile(filePath string, data any) error {
jsonBytes, err := json.Marshal(data)
if err != nil {
return err
}
return os.WriteFile(filePath, jsonBytes, 0664)
}
// WritePretty write pretty data to JSON file
func WritePretty(filePath string, data any) error {
bs, err := json.MarshalIndent(data, "", " ")
if err != nil {
return err
}
return os.WriteFile(filePath, bs, 0664)
}
// ReadFile Read JSON file data
func ReadFile(filePath string, v any) error {
file, err := os.Open(filePath)
if err != nil {
return err
}
defer file.Close()
return json.NewDecoder(file).Decode(v)
}
// Pretty JSON string and return
func Pretty(v any) (string, error) {
out, err := json.MarshalIndent(v, "", " ")
return string(out), err
}
// MustPretty data to JSON string, will panic on error
func MustPretty(v any) string {
out, err := json.MarshalIndent(v, "", " ")
if err != nil {
panic(err)
}
return string(out)
}
// Mapping src data(map,struct) to dst struct use json tags.
//
// On src, dst both is struct, equivalent to merging two structures (src should be a subset of dsc)
func Mapping(src, dst any) error {
bts, err := json.Marshal(src)
if err != nil {
return err
}
return Decode(bts, dst)
}
// IsJSON check if the string is valid JSON. (Note: uses json.Valid)
func IsJSON(s string) bool {
if s == "" {
return false
}
return json.Valid([]byte(s))
}
// IsJSONFast simple and fast check input is valid JSON array or object.
func IsJSONFast(s string) bool {
ln := len(s)
if ln < 2 {
return false
}
if ln == 2 {
return s == "{}" || s == "[]"
}
// object
if s[0] == '{' {
return s[ln-1] == '}' && s[1] == '"'
}
// array
return s[0] == '[' && s[ln-1] == ']'
}
// IsArray check if the string is valid JSON array.
func IsArray(s string) bool {
ln := len(s)
if ln < 2 {
return false
}
return s[0] == '[' && s[ln-1] == ']'
}
// IsObject check if the string is valid JSON object.
func IsObject(s string) bool {
ln := len(s)
if ln < 2 {
return false
}
if ln == 2 {
return s == "{}"
}
// object
if s[0] == '{' {
return s[ln-1] == '}' && s[1] == '"'
}
return false
}
// `(?s:` enable match multi line
var jsonMLComments = regexp.MustCompile(`(?s:/\*.*?\*/\s*)`)
// StripComments strip comments for a JSON string
func StripComments(src string) string {
// multi line comments
if strings.Contains(src, "/*") {
src = jsonMLComments.ReplaceAllString(src, "")
}
// single line comments
if !strings.Contains(src, "//") {
return strings.TrimSpace(src)
}
// strip inline comments
var s scanner.Scanner
s.Init(strings.NewReader(src))
s.Filename = "comments"
s.Mode ^= scanner.SkipComments // don't skip comments
buf := new(bytes.Buffer)
for tok := s.Scan(); tok != scanner.EOF; tok = s.Scan() {
txt := s.TokenText()
if !strings.HasPrefix(txt, "//") && !strings.HasPrefix(txt, "/*") {
buf.WriteString(txt)
// } else {
// fmt.Printf("%s: %s\n", s.Position, txt)
}
}
return buf.String()
}