是否可以在未知的json结构中重写字符串?

是否可以在未知的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包来实现这一点?

我需要解析任意json,编码/重写任何长度超过85个字符的字符串键或值(想想一种短URL服务),并将其封送回原始json。 e、 g.像这样的文档
{“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
?是。语言是围棋