检查字符串是否为JSON格式

检查字符串是否为JSON格式,json,go,Json,Go,如何检查给定字符串是否为多个json字符串的形式,并用空格/换行符分隔 例如, 给定:“test”123{“Name”:“mike”}(3个json连空格) 返回:true,因为每个项(“test”123和{“Name”:“mike”})都是有效的json 在Go中,我可以编写一个O(N^2)函数,如: // check given string is json or multiple json concatenated with space/newline func validateJSON(

如何检查给定字符串是否为多个json字符串的形式,并用空格/换行符分隔

例如,
给定:
“test”123{“Name”:“mike”}
(3个json连空格)
返回:
true
,因为每个项(
“test”
123
{“Name”:“mike”}
)都是有效的json

在Go中,我可以编写一个O(N^2)函数,如:

// check given string is json or multiple json concatenated with space/newline
func validateJSON(str string) error {
    // only one json string
    if isJSON(str) {
        return nil
    }
    // multiple json string concatenate with spaces
    str = strings.TrimSpace(str)
    arr := []rune(str)
    start := 0
    end := 0
    for start < len(str) {
        for end < len(str) && !unicode.IsSpace(arr[end]) {
            end++
        }
        substr := str[start:end]
        if isJSON(substr) {
            for end < len(str) && unicode.IsSpace(arr[end]) {
                end++
            }
            start = end
        } else {
            if end == len(str) {
                return errors.New("error when parsing input: " + substr)
            }
            for end < len(str) && unicode.IsSpace(arr[end]) {
                end++
            }
        }
    }
    return nil
}

func isJSON(str string) bool {
    var js json.RawMessage
    return json.Unmarshal([]byte(str), &js) == nil
}
//检查给定字符串是json还是多个json与空格/换行符连接
func validateJSON(str字符串)错误{
//只有一个json字符串
如果是isJSON(str){
归零
}
//多个json字符串与空格连接
str=strings.TrimSpace(str)
arr:=[]符文(str)
开始:=0
结束:=0
对于开始

但这对于大的投入是行不通的

正如沃尔克在评论中提到的,使用*json.Decoder依次解码输入中的所有json文档:

package main

import (
    "encoding/json"
    "io"
    "log"
    "strings"
)

func main() {
    input := `"test" 123 {"Name": "mike"}`
    dec := json.NewDecoder(strings.NewReader(input))

    for {
            var x json.RawMessage
            switch err := dec.Decode(&x); err {
            case nil:
                    // not done yet
            case io.EOF:
                    return // success
            default:
                    log.Fatal(err)
            }
    }
}

在操场上试试:

有两种选择。从编码的角度来看,最简单的方法就是正常解码JSON字符串。您可以通过解码到空结构来提高效率:

package main

import "encoding/json"

func main() {
    input := []byte(`{"a":"b", "c": 123}`)
    var x struct{}
    if err := json.Unmarshal(input, &x); err != nil {
        panic(err)
    }

    input = []byte(`{"a":"b", "c": 123}xxx`) // This one fails
    if err := json.Unmarshal(input, &x); err != nil {
        panic(err)
    }
}
()

这种方法有几个潜在的缺点:

  • 它只适用于单个JSON对象。也就是说,对象列表(如问题中所要求的)将失败,而无需附加逻辑
  • 正如@icza在注释中指出的,它只适用于JSON对象,因此裸数组、数字或字符串将失败。为了适应这些类型,必须使用
    接口{}
    ,这可能导致一些严重的性能损失
  • 扔掉
    x
    值仍然必须分配,并且工作表下可能至少有一个反射调用,这可能会对某些工作负载带来明显的性能损失
鉴于这些限制,我建议使用第二个选项:遍历整个JSON输入,忽略实际内容。使用标准库可以简化此操作:

()

试试:


因此,如果顶级空格(引号外的字符串)被逗号替换,并且整个内容被方括号包围,那么整个内容将是有效的JSON?我不知道这是一个学术或个人练习,但函数已经存在。是@TedHopp。我还希望输入的json字符串用逗号>分隔。谢谢@squiguy,Vald不会有帮助,因为输入不是json,而是多个json与空格/换行符连接。您是否反复尝试在流上编码/json.Decoder?因为我认为解码器的全部目的是通过这样的JSON元素流进行解码。将其解码为
结构{}
——这将仍然验证JSON输入,但不会分配任何内存。@Flimzy,但如果JSON文档不是对象,则会失败。然而,json.RawMessage可能仍然比接口{}好得多。我将更新答案。实际上,json.RawMessage是结构{}的功能和接口{}的性能之间的一个很好的折衷。虽然理想的做法仍然是根本不分配任何内存。使用无操作解组方法的自定义类型可以实现这一点。但是迭代令牌可能更好。第一个选项有一些缺点,例如,它只能解组JSON对象(并且无法解组有效值,如
123
“abc”
或JSON对象),因此要使其工作,需要
接口{}
来处理所有情况。第二个选项没有这个限制,只获取代币是个好主意。@icza:观察得好。谢谢@Flimzy,选项2使用代币帮助我优雅地解决了问题。我用150KB的输入字符串测试了它,速度不到秒。
package main

import (
    "bytes"
    "encoding/json"
    "io"
)

func main() {
        input := []byte(`{"a":"b", "c": 123}`)
        dec := json.NewDecoder(bytes.NewReader(input))
        for {
            _, err := dec.Token()
            if err == io.EOF {
                break // End of input, valid JSON
            }
            if err != nil {
                panic(err) // Invalid input
            }
        }

        input = []byte(`{"a":"b", "c": 123}xxx`) // This input fails
        dec = json.NewDecoder(bytes.NewReader(input))
        for {
            _, err := dec.Token()
            if err == io.EOF {
                break // End of input, valid JSON
            }
            if err != nil {
                panic(err) // Invalid input
            }
        }
}
s := `"test" 123 {"Name": "mike"}`

var sc fastjson.Scanner
sc.Init(s)

// Iterate over a stream of json objects
for sc.Next() {}
if sc.Error() != nil {
    fmt.Println("ok")
} else {
    fmt.Println("false")
}