perf: json format compatible with nonstandard value
This commit is contained in:
parent
4dd52a8c8e
commit
e5fed29427
|
@ -1,9 +1,8 @@
|
||||||
package convutil
|
package convutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
strutil "tinyrdm/backend/utils/string"
|
||||||
)
|
)
|
||||||
|
|
||||||
type JsonConvert struct{}
|
type JsonConvert struct{}
|
||||||
|
@ -16,18 +15,11 @@ func (JsonConvert) Decode(str string) (string, bool) {
|
||||||
trimedStr := strings.TrimSpace(str)
|
trimedStr := strings.TrimSpace(str)
|
||||||
if (strings.HasPrefix(trimedStr, "{") && strings.HasSuffix(trimedStr, "}")) ||
|
if (strings.HasPrefix(trimedStr, "{") && strings.HasSuffix(trimedStr, "}")) ||
|
||||||
(strings.HasPrefix(trimedStr, "[") && strings.HasSuffix(trimedStr, "]")) {
|
(strings.HasPrefix(trimedStr, "[") && strings.HasSuffix(trimedStr, "]")) {
|
||||||
var out bytes.Buffer
|
return strutil.JSONBeautify(trimedStr, " "), true
|
||||||
if err := json.Indent(&out, []byte(trimedStr), "", " "); err == nil {
|
|
||||||
return out.String(), true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return str, false
|
return str, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (JsonConvert) Encode(str string) (string, bool) {
|
func (JsonConvert) Encode(str string) (string, bool) {
|
||||||
var dst bytes.Buffer
|
return strutil.JSONMinify(str), true
|
||||||
if err := json.Compact(&dst, []byte(str)); err != nil {
|
|
||||||
return str, false
|
|
||||||
}
|
|
||||||
return dst.String(), true
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,9 @@ package convutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
strutil "tinyrdm/backend/utils/string"
|
||||||
"unicode"
|
"unicode"
|
||||||
"unicode/utf16"
|
"unicode/utf16"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
@ -20,22 +20,16 @@ func (UnicodeJsonConvert) Decode(str string) (string, bool) {
|
||||||
trimedStr := strings.TrimSpace(str)
|
trimedStr := strings.TrimSpace(str)
|
||||||
if (strings.HasPrefix(trimedStr, "{") && strings.HasSuffix(trimedStr, "}")) ||
|
if (strings.HasPrefix(trimedStr, "{") && strings.HasSuffix(trimedStr, "}")) ||
|
||||||
(strings.HasPrefix(trimedStr, "[") && strings.HasSuffix(trimedStr, "]")) {
|
(strings.HasPrefix(trimedStr, "[") && strings.HasSuffix(trimedStr, "]")) {
|
||||||
var out bytes.Buffer
|
resultStr := strutil.JSONBeautify(trimedStr, " ")
|
||||||
if err := json.Indent(&out, []byte(trimedStr), "", " "); err == nil {
|
if quoteStr, ok := UnquoteUnicodeJson([]byte(resultStr)); ok {
|
||||||
if quoteStr, ok := UnquoteUnicodeJson(out.Bytes()); ok {
|
|
||||||
return string(quoteStr), true
|
return string(quoteStr), true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return str, false
|
return str, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (UnicodeJsonConvert) Encode(str string) (string, bool) {
|
func (UnicodeJsonConvert) Encode(str string) (string, bool) {
|
||||||
var dst bytes.Buffer
|
return strutil.JSONMinify(str), true
|
||||||
if err := json.Compact(&dst, []byte(str)); err != nil {
|
|
||||||
return str, false
|
|
||||||
}
|
|
||||||
return dst.String(), true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func UnquoteUnicodeJson(s []byte) ([]byte, bool) {
|
func UnquoteUnicodeJson(s []byte) ([]byte, bool) {
|
||||||
|
|
|
@ -0,0 +1,158 @@
|
||||||
|
package strutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Convert from https://github.com/ObuchiYuki/SwiftJSONFormatter
|
||||||
|
|
||||||
|
// ArrayIterator defines the iterator for an array
|
||||||
|
type ArrayIterator[T any] struct {
|
||||||
|
array []T
|
||||||
|
head int
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewArrayIterator initializes a new ArrayIterator with the given array
|
||||||
|
func NewArrayIterator[T any](array []T) *ArrayIterator[T] {
|
||||||
|
return &ArrayIterator[T]{
|
||||||
|
array: array,
|
||||||
|
head: -1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasNext returns true if there are more elements to iterate over
|
||||||
|
func (it *ArrayIterator[T]) HasNext() bool {
|
||||||
|
return it.head+1 < len(it.array)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PeekNext returns the next element without advancing the iterator
|
||||||
|
func (it *ArrayIterator[T]) PeekNext() *T {
|
||||||
|
if it.head+1 < len(it.array) {
|
||||||
|
return &it.array[it.head+1]
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next returns the next element and advances the iterator
|
||||||
|
func (it *ArrayIterator[T]) Next() *T {
|
||||||
|
defer func() {
|
||||||
|
it.head++
|
||||||
|
}()
|
||||||
|
return it.PeekNext()
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSONBeautify formats a JSON string with indentation
|
||||||
|
func JSONBeautify(value string, indent string) string {
|
||||||
|
if len(indent) <= 0 {
|
||||||
|
indent = " "
|
||||||
|
}
|
||||||
|
return format(value, indent, "\n", " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSONMinify formats a JSON string by removing all unnecessary whitespace
|
||||||
|
func JSONMinify(value string) string {
|
||||||
|
return format(value, "", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// format applies the specified formatting to a JSON string
|
||||||
|
func format(value string, indent string, newLine string, separator string) string {
|
||||||
|
var formatted strings.Builder
|
||||||
|
chars := NewArrayIterator([]rune(value))
|
||||||
|
indentLevel := 0
|
||||||
|
|
||||||
|
for chars.HasNext() {
|
||||||
|
if char := chars.Next(); char != nil {
|
||||||
|
switch *char {
|
||||||
|
case '{', '[':
|
||||||
|
formatted.WriteRune(*char)
|
||||||
|
consumeWhitespaces(chars)
|
||||||
|
peeked := chars.PeekNext()
|
||||||
|
if peeked != nil && (*peeked == '}' || *peeked == ']') {
|
||||||
|
chars.Next()
|
||||||
|
formatted.WriteRune(*peeked)
|
||||||
|
} else {
|
||||||
|
indentLevel++
|
||||||
|
formatted.WriteString(newLine)
|
||||||
|
formatted.WriteString(strings.Repeat(indent, indentLevel))
|
||||||
|
}
|
||||||
|
case '}', ']':
|
||||||
|
indentLevel--
|
||||||
|
formatted.WriteString(newLine)
|
||||||
|
formatted.WriteString(strings.Repeat(indent, max(0, indentLevel)))
|
||||||
|
formatted.WriteRune(*char)
|
||||||
|
case '"':
|
||||||
|
str := consumeString(chars)
|
||||||
|
//str = convertUnicodeString(str)
|
||||||
|
formatted.WriteString(str)
|
||||||
|
case ',':
|
||||||
|
consumeWhitespaces(chars)
|
||||||
|
formatted.WriteRune(',')
|
||||||
|
peeked := chars.PeekNext()
|
||||||
|
if peeked != nil && *peeked != '}' && *peeked != ']' {
|
||||||
|
formatted.WriteString(newLine)
|
||||||
|
formatted.WriteString(strings.Repeat(indent, max(0, indentLevel)))
|
||||||
|
}
|
||||||
|
case ':':
|
||||||
|
formatted.WriteString(":" + separator)
|
||||||
|
default:
|
||||||
|
if !unicode.IsSpace(*char) {
|
||||||
|
formatted.WriteRune(*char)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return formatted.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// consumeWhitespaces advances the iterator past any whitespace characters
|
||||||
|
func consumeWhitespaces(iter *ArrayIterator[rune]) {
|
||||||
|
for iter.HasNext() {
|
||||||
|
if peeked := iter.PeekNext(); peeked != nil && unicode.IsSpace(*peeked) {
|
||||||
|
iter.Next()
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// consumeString consumes a JSON string value from the iterator
|
||||||
|
func consumeString(iter *ArrayIterator[rune]) string {
|
||||||
|
var sb strings.Builder
|
||||||
|
sb.WriteRune('"')
|
||||||
|
escaping := false
|
||||||
|
|
||||||
|
for iter.HasNext() {
|
||||||
|
if char := iter.Next(); char != nil {
|
||||||
|
if *char == '\n' {
|
||||||
|
return sb.String() // Unterminated string
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.WriteRune(*char)
|
||||||
|
|
||||||
|
if escaping {
|
||||||
|
escaping = false
|
||||||
|
} else {
|
||||||
|
if *char == '\\' {
|
||||||
|
escaping = true
|
||||||
|
}
|
||||||
|
if *char == '"' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertUnicodeString(str string) string {
|
||||||
|
// TODO: quote UTF-16 characters
|
||||||
|
//if len(str) > 2 {
|
||||||
|
// if unqStr, err := strconv.Unquote(str); err == nil {
|
||||||
|
// return strconv.Quote(unqStr)
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
return str
|
||||||
|
}
|
Loading…
Reference in New Issue