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  }