检查字符串是否为JSON格式
如何检查给定字符串是否为多个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(
给定:
“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?我不知道这是一个学术或个人练习,但函数已经存在。是@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")
}