github.com/sohaha/zlsgo@v1.7.13-0.20240501141223-10dd1a906f76/zjson/format.go (about) 1 package zjson 2 3 import ( 4 "bytes" 5 "sort" 6 7 "github.com/sohaha/zlsgo/zstring" 8 ) 9 10 type ( 11 Map map[string]string 12 StFormatOptions struct { 13 Prefix string 14 Indent string 15 Width int 16 SortKeys bool 17 } 18 pair struct { 19 ks, kd int 20 vs, vd int 21 } 22 byKey struct { 23 json []byte 24 pairs []pair 25 sorted bool 26 } 27 ) 28 29 var ( 30 DefOptions = &StFormatOptions{Width: 80, Prefix: "", Indent: " ", SortKeys: false} 31 Matches = []Map{ 32 {"start": "//", "end": "\n"}, 33 {"start": "/*", "end": "*/"}, 34 } 35 ) 36 37 func Format(json []byte) []byte { return FormatOptions(json, nil) } 38 39 func FormatOptions(json []byte, opts *StFormatOptions) []byte { 40 if opts == nil { 41 opts = DefOptions 42 } 43 buf := make([]byte, 0, len(json)) 44 if len(opts.Prefix) != 0 { 45 buf = append(buf, opts.Prefix...) 46 } 47 buf, _, _, _ = appendAny(buf, json, 0, true, 48 opts.Width, opts.Prefix, opts.Indent, opts.SortKeys, 49 0, 0, -1) 50 if len(buf) > 0 { 51 buf = append(buf, '\n') 52 } 53 return buf 54 } 55 56 func Ugly(json []byte) []byte { 57 jsonStr, err := Discard(zstring.Bytes2String(json)) 58 if err == nil { 59 json = zstring.String2Bytes(jsonStr) 60 } 61 buf := make([]byte, 0, len(json)) 62 return ugly(buf, json) 63 } 64 65 func ugly(dst, src []byte) []byte { 66 dst = dst[:0] 67 for i := 0; i < len(src); i++ { 68 if src[i] > ' ' { 69 dst = append(dst, src[i]) 70 if src[i] == '"' { 71 for i = i + 1; i < len(src); i++ { 72 dst = append(dst, src[i]) 73 if src[i] == '"' { 74 j := i - 1 75 for ; ; j-- { 76 if src[j] != '\\' { 77 break 78 } 79 } 80 if (j-i)%2 != 0 { 81 break 82 } 83 } 84 } 85 } 86 } 87 } 88 return dst 89 } 90 91 func appendAny(buf, json []byte, i int, pretty bool, width int, prefix, indent string, sortkeys bool, tabs, nl, max int) ([]byte, int, int, bool) { 92 for ; i < len(json); i++ { 93 if json[i] <= ' ' { 94 continue 95 } 96 if json[i] == '"' { 97 return appendString(buf, json, i, nl) 98 } 99 if (json[i] >= '0' && json[i] <= '9') || json[i] == '-' { 100 return appendNumber(buf, json, i, nl) 101 } 102 if json[i] == '{' { 103 return appendObject(buf, json, i, '{', '}', pretty, width, prefix, indent, sortkeys, tabs, nl, max) 104 } 105 if json[i] == '[' { 106 return appendObject(buf, json, i, '[', ']', pretty, width, prefix, indent, sortkeys, tabs, nl, max) 107 } 108 switch json[i] { 109 case 't': 110 return append(buf, 't', 'r', 'u', 'e'), i + 4, nl, true 111 case 'f': 112 return append(buf, 'f', 'a', 'l', 's', 'e'), i + 5, nl, true 113 case 'n': 114 return append(buf, 'n', 'u', 'l', 'l'), i + 4, nl, true 115 } 116 } 117 return buf, i, nl, true 118 } 119 120 func (arr *byKey) Len() int { 121 return len(arr.pairs) 122 } 123 124 func (arr *byKey) Less(i, j int) bool { 125 key1 := arr.json[arr.pairs[i].ks+1 : arr.pairs[i].kd-1] 126 key2 := arr.json[arr.pairs[j].ks+1 : arr.pairs[j].kd-1] 127 return zstring.Bytes2String(key1) < zstring.Bytes2String(key2) 128 } 129 130 func (arr *byKey) Swap(i, j int) { 131 arr.pairs[i], arr.pairs[j] = arr.pairs[j], arr.pairs[i] 132 arr.sorted = true 133 } 134 135 func appendObject(buf, json []byte, i int, open, close byte, pretty bool, width int, prefix, indent string, sortkeys bool, tabs, nl, max int) ([]byte, int, int, bool) { 136 var ok bool 137 if width > 0 { 138 if pretty && open == '[' && max == -1 { 139 max := width - (len(buf) - nl) 140 if max > 3 { 141 s1, s2 := len(buf), i 142 buf, i, _, ok = appendObject(buf, json, i, '[', ']', false, width, prefix, "", sortkeys, 0, 0, max) 143 if ok && len(buf)-s1 <= max { 144 return buf, i, nl, true 145 } 146 buf = buf[:s1] 147 i = s2 148 } 149 } else if max != -1 && open == '{' { 150 return buf, i, nl, false 151 } 152 } 153 buf = append(buf, open) 154 i++ 155 var pairs []pair 156 if open == '{' && sortkeys { 157 pairs = make([]pair, 0, 8) 158 } 159 var n int 160 for ; i < len(json); i++ { 161 if json[i] <= ' ' { 162 continue 163 } 164 if json[i] == close { 165 if pretty { 166 if open == '{' && sortkeys { 167 buf = sortPairs(json, buf, pairs) 168 } 169 if n > 0 { 170 nl = len(buf) 171 buf = append(buf, '\n') 172 } 173 if buf[len(buf)-1] != open { 174 buf = appendTabs(buf, prefix, indent, tabs) 175 } 176 } 177 buf = append(buf, close) 178 return buf, i + 1, nl, open != '{' 179 } 180 if open == '[' || json[i] == '"' { 181 if n > 0 { 182 buf = append(buf, ',') 183 if width != -1 && open == '[' { 184 buf = append(buf, ' ') 185 } 186 } 187 var p pair 188 if pretty { 189 nl = len(buf) 190 buf = append(buf, '\n') 191 if open == '{' && sortkeys { 192 p.ks = i 193 p.vs = len(buf) 194 } 195 buf = appendTabs(buf, prefix, indent, tabs+1) 196 } 197 if open == '{' { 198 buf, i, nl, _ = appendString(buf, json, i, nl) 199 if sortkeys { 200 p.kd = i 201 } 202 buf = append(buf, ':') 203 if pretty { 204 buf = append(buf, ' ') 205 } 206 } 207 buf, i, nl, ok = appendAny(buf, json, i, pretty, width, prefix, indent, sortkeys, tabs+1, nl, max) 208 if max != -1 && !ok { 209 return buf, i, nl, false 210 } 211 if pretty && open == '{' && sortkeys { 212 p.vd = len(buf) 213 if p.ks > p.kd || p.vs > p.vd { 214 sortkeys = false 215 } else { 216 pairs = append(pairs, p) 217 } 218 } 219 i-- 220 n++ 221 } 222 } 223 return buf, i, nl, open != '{' 224 } 225 226 func sortPairs(json, buf []byte, pairs []pair) []byte { 227 if len(pairs) == 0 { 228 return buf 229 } 230 vstart := pairs[0].vs 231 vend := pairs[len(pairs)-1].vd 232 arr := byKey{sorted: false, json: json, pairs: pairs} 233 sort.Sort(&arr) 234 if !arr.sorted { 235 return buf 236 } 237 nbuf := make([]byte, 0, vend-vstart) 238 for i, p := range pairs { 239 nbuf = append(nbuf, buf[p.vs:p.vd]...) 240 if i < len(pairs)-1 { 241 nbuf = append(nbuf, ',') 242 nbuf = append(nbuf, '\n') 243 } 244 } 245 return append(buf[:vstart], nbuf...) 246 } 247 248 func appendString(buf, json []byte, i, nl int) ([]byte, int, int, bool) { 249 s := i 250 i++ 251 for ; i < len(json); i++ { 252 if json[i] == '"' { 253 var sc int 254 for j := i - 1; j > s; j-- { 255 if json[j] == '\\' { 256 sc++ 257 } else { 258 break 259 } 260 } 261 if sc%2 == 1 { 262 continue 263 } 264 i++ 265 break 266 } 267 } 268 return append(buf, json[s:i]...), i, nl, true 269 } 270 271 func appendNumber(buf, json []byte, i, nl int) ([]byte, int, int, bool) { 272 s := i 273 i++ 274 for ; i < len(json); i++ { 275 if json[i] <= ' ' || json[i] == ',' || json[i] == ':' || json[i] == ']' || json[i] == '}' { 276 break 277 } 278 } 279 return append(buf, json[s:i]...), i, nl, true 280 } 281 282 func appendTabs(buf []byte, prefix, indent string, tabs int) []byte { 283 if len(prefix) != 0 { 284 buf = append(buf, prefix...) 285 } 286 if len(indent) == 2 && indent[0] == ' ' && indent[1] == ' ' { 287 for i := 0; i < tabs; i++ { 288 buf = append(buf, ' ', ' ') 289 } 290 } else { 291 for i := 0; i < tabs; i++ { 292 buf = append(buf, indent...) 293 } 294 } 295 return buf 296 } 297 298 func Discard(json string) (string, error) { 299 var ( 300 buffer bytes.Buffer 301 flag int 302 v rune 303 protected bool 304 ) 305 runes := []rune(json) 306 flag = -1 307 for i := 0; i < len(runes); { 308 v = runes[i] 309 if flag == -1 { 310 for f, v := range Matches { 311 l := match(&runes, i, v["start"]) 312 if l != 0 { 313 flag = f 314 i += l 315 break 316 } 317 } 318 if flag == -1 { 319 if protected { 320 buffer.WriteRune(v) 321 if v == '"' { 322 protected = true 323 } 324 } else { 325 r := filter(v) 326 if r != 0 { 327 buffer.WriteRune(v) 328 } 329 } 330 } else { 331 continue 332 } 333 } else { 334 l := match(&runes, i, Matches[flag]["end"]) 335 if l != 0 { 336 flag = -1 337 i += l 338 continue 339 } 340 } 341 i++ 342 } 343 return buffer.String(), nil 344 } 345 346 func filter(v rune) rune { 347 switch v { 348 case ' ': 349 case '\n': 350 case '\t': 351 default: 352 return v 353 } 354 return 0 355 } 356 357 func match(runes *[]rune, i int, dst string) int { 358 dstLen := len([]rune(dst)) 359 if len(*runes)-i >= dstLen && string((*runes)[i:i+dstLen]) == dst { 360 return dstLen 361 } 362 return 0 363 }