是否可以在未知的json结构中重写字符串?
我需要解析任意json,编码/重写任何长度超过85个字符的字符串键或值(想想一种短URL服务),并将其封送回原始json。 e、 g.像这样的文档是否可以在未知的json结构中重写字符串?,json,go,Json,Go,我需要解析任意json,编码/重写任何长度超过85个字符的字符串键或值(想想一种短URL服务),并将其封送回原始json。 e、 g.像这样的文档{“Name”:“Ed”,“Text”:“long characters….85 chars”}应该变成像这样的{“Name”:“Ed”,“Text”:”short://ID=3403“}。这个例子很简单,但我必须处理具有嵌套对象和数组以及基本未知结构的复杂结构 我的问题是:是否可以使用已知的库或甚至是标准的encoding/json包来实现这一点?
{“Name”:“Ed”,“Text”:“long characters….85 chars”}
应该变成像这样的{“Name”:“Ed”,“Text”:”short://ID=3403“}
。这个例子很简单,但我必须处理具有嵌套对象和数组以及基本未知结构的复杂结构
我的问题是:是否可以使用已知的库或甚至是标准的encoding/json包来实现这一点?
我实际上需要的是
类型字符串上接口的等效实现,但我们知道这是不可能的,所以我想知道我还有什么其他选择(除了分叉标准编码/json包)是的,可以使用标准库和一点代码
解组到接口{}
var v interface{}
if err := json.Unmarshal(data, &v); err != nil {
// handle error
}
遍历取消编组的值,缩短字符串并边走边重写:
func shorten(v interface{}) interface{} {
switch v := v.(type) {
case []interface{}:
for i, e := range v {
v[i] = shorten(e)
}
return v
case map[string]interface{}:
m := make(map[string]interface{})
for k, e := range v {
m[shortenString(k)] = shorten(e)
}
return m
case string:
return shortenString(v)
default:
return v
}
}
函数shorten
调用shortenString(s string)string
将长字符串转换为short://ID=xxx
将值封送回JSON:
p, err := json.Marshal(shorten(v))
if err != nil {
// handle error
}
// p is a []byte
fmt.Printf("%s\n", p)
是的,可以使用标准库和一点代码
解组到接口{}
var v interface{}
if err := json.Unmarshal(data, &v); err != nil {
// handle error
}
遍历取消编组的值,缩短字符串并边走边重写:
func shorten(v interface{}) interface{} {
switch v := v.(type) {
case []interface{}:
for i, e := range v {
v[i] = shorten(e)
}
return v
case map[string]interface{}:
m := make(map[string]interface{})
for k, e := range v {
m[shortenString(k)] = shorten(e)
}
return m
case string:
return shortenString(v)
default:
return v
}
}
函数shorten
调用shortenString(s string)string
将长字符串转换为short://ID=xxx
将值封送回JSON:
p, err := json.Marshal(shorten(v))
if err != nil {
// handle error
}
// p is a []byte
fmt.Printf("%s\n", p)
如果要求将所有长度超过85个字符的字符串替换为JSON中的新缩短版本,并且如果您可以假设JSON是有效的JSON(即,如果不要求您在输入无效时进行诊断),那么您可以使用单个regexp替换
有效JSON中带引号的字符串可以与
/"([^\\"]|\\.)*"/
因此,您可以将此模式的所有实例替换为可能缩短的版本。如果要求将JSON中所有长度超过85个字符的字符串替换为新的缩短版本,并且可以假设JSON是有效的JSON(即,如果不需要在输入无效时进行诊断)然后您可以只使用一个regexp替换
有效JSON中带引号的字符串可以与
/"([^\\"]|\\.)*"/
因此,您可以用可能缩短的版本替换此模式的所有实例。这里有一种方法(已测试),它使用了json.Decoder
的方法,并避免将整个数据结构反序列化到内存中。这样做主要是为了好玩,也为了说明如何使用该方法,但是如果JSON文档非常大,并且希望避免内存开销,那么它可能会有一些用处
// For example
r, w := os.Stdin, os.Stdout
dec := json.NewDecoder(r)
// Avoids any round-trip loss by leaving numbers un-parsed
dec.UseNumber()
// Current state (in an object or in an array; following the open
// delim, or a key, or a value). The decoder has its own stack pretty
// like this one, but it's private, so keep our own.
const (
jsonArrayStart = iota
jsonArrayVal
jsonObjectStart
jsonObjectKey
jsonObjectVal
)
stack := []byte{}
for {
t, err := dec.Token()
if err == io.EOF {
break
} else if err != nil {
log.Fatal(err)
}
switch val := t.(type) {
case json.Delim:
// Copy delimiters out, and push/pop the state stack as appropriate
w.WriteString(string([]rune{rune(val)}))
switch val {
case '[':
stack = append(stack, jsonArrayStart)
case '{':
stack = append(stack, jsonObjectStart)
case ']', '}':
stack = stack[:len(stack)-1]
}
// The rest of the cases just copy values out
case nil:
w.WriteString("null")
case json.Number:
w.WriteString(string(val))
case bool:
if val {
w.WriteString("true")
} else {
w.WriteString("false")
}
case string:
// Modify strings if called for (shortenString needs to be provided)
if len(val) >= 85 {
val = shortenString(val)
}
encoded, err := json.Marshal(val)
if err != nil {
log.Fatal(err)
}
w.Write(encoded)
}
if dec.More() {
// If there's more in the current array/object, write a colon or comma
// (if we just wrote a key/value), and set the next state.
// Arrays start with a value, and follow with more values.
// Objects start with a key and alternate between key and value.
switch stack[len(stack)-1] {
case jsonArrayStart:
stack[len(stack)-1] = jsonArrayVal
case jsonArrayVal:
w.WriteString(",")
// State remains jsonArrayVal
case jsonObjectStart:
stack[len(stack)-1] = jsonObjectKey
case jsonObjectKey:
w.WriteString(":")
stack[len(stack)-1] = jsonObjectVal
case jsonObjectVal:
w.WriteString(",")
stack[len(stack)-1] = jsonObjectKey
}
} else {
if len(stack) == 0 {
// End after the first complete value (array/object) in the stream
break
}
if stack[len(stack)-1] == jsonObjectKey {
// Should never happen
log.Fatal("Object key without a value?")
}
}
}
这里有一种方法(经过测试),它使用了json.Decoder
的方法,避免了将整个数据结构反序列化到内存中。这样做主要是为了好玩,也为了说明如何使用该方法,但是如果JSON文档非常大,并且希望避免内存开销,那么它可能会有一些用处
// For example
r, w := os.Stdin, os.Stdout
dec := json.NewDecoder(r)
// Avoids any round-trip loss by leaving numbers un-parsed
dec.UseNumber()
// Current state (in an object or in an array; following the open
// delim, or a key, or a value). The decoder has its own stack pretty
// like this one, but it's private, so keep our own.
const (
jsonArrayStart = iota
jsonArrayVal
jsonObjectStart
jsonObjectKey
jsonObjectVal
)
stack := []byte{}
for {
t, err := dec.Token()
if err == io.EOF {
break
} else if err != nil {
log.Fatal(err)
}
switch val := t.(type) {
case json.Delim:
// Copy delimiters out, and push/pop the state stack as appropriate
w.WriteString(string([]rune{rune(val)}))
switch val {
case '[':
stack = append(stack, jsonArrayStart)
case '{':
stack = append(stack, jsonObjectStart)
case ']', '}':
stack = stack[:len(stack)-1]
}
// The rest of the cases just copy values out
case nil:
w.WriteString("null")
case json.Number:
w.WriteString(string(val))
case bool:
if val {
w.WriteString("true")
} else {
w.WriteString("false")
}
case string:
// Modify strings if called for (shortenString needs to be provided)
if len(val) >= 85 {
val = shortenString(val)
}
encoded, err := json.Marshal(val)
if err != nil {
log.Fatal(err)
}
w.Write(encoded)
}
if dec.More() {
// If there's more in the current array/object, write a colon or comma
// (if we just wrote a key/value), and set the next state.
// Arrays start with a value, and follow with more values.
// Objects start with a key and alternate between key and value.
switch stack[len(stack)-1] {
case jsonArrayStart:
stack[len(stack)-1] = jsonArrayVal
case jsonArrayVal:
w.WriteString(",")
// State remains jsonArrayVal
case jsonObjectStart:
stack[len(stack)-1] = jsonObjectKey
case jsonObjectKey:
w.WriteString(":")
stack[len(stack)-1] = jsonObjectVal
case jsonObjectVal:
w.WriteString(",")
stack[len(stack)-1] = jsonObjectKey
}
} else {
if len(stack) == 0 {
// End after the first complete value (array/object) in the stream
break
}
if stack[len(stack)-1] == jsonObjectKey {
// Should never happen
log.Fatal("Object key without a value?")
}
}
}
它必须在go
中吗?是的。语言是GOI,它必须在go
?是。语言是围棋