如何为bufio.Scanner编写自定义splitFunc以扫描JSON对象
使用bufio.Scanner按完整JSON对象分割输入
我需要用bufio.Scanner从输入中每次读取一个完整的JSON对象,输入中可能同时包含完整和不完整的JSON结构,比如:
{ "some_object": "name", "some_fileds": {} } { "some_object": }
只需要提取第一个完整的JSON对象,对于不完整的则等待后续输入补全后再处理。
最初我尝试自己实现splitJSON分割函数,但效果很差:
func splitJSON( bb []byte, atEOF bool, ) (advance int, token []byte, err error) { print(string(bb)) if len(bb) < 10 { return 0, nil, nil } var nested, from, to int var end bool for i, b := range bb { if string(b) == "{" { if end { to = i break } if nested == 0 { from = i } nested++ } if string(b) == "}" { nested-- if nested == 0 { to = i end = true } } } if atEOF { return len(bb), bb, nil } return len(bb[from:to]), bb[from:to], nil }
最终解决方案
借助标准库的json.Decoder来处理JSON的解析逻辑,实现了正确的分割函数:
func splitJSON(data []byte, atEOF bool) (advance int, token []byte, err error) { if atEOF && len(data) == 0 { return 0, nil, nil } reader := bytes.NewReader(data) dec := json.NewDecoder(reader) var raw json.RawMessage if err := dec.Decode(&raw); err != nil { // 解析失败,说明当前数据不足以构成完整JSON,返回0等待更多输入 return 0, nil, nil } // 前进的字节数为RawMessage的长度+1(跳过JSON对象后的换行/空格分隔符) return len(raw) + 1, raw, nil }
说明
这个方法的核心是利用json.Decoder的原生解析能力,它会自动处理JSON的嵌套结构、转义字符等边界情况,比手动计数大括号的方式更可靠:
- 当输入数据不足以解析出完整JSON时,
Decode返回错误,此时分割函数返回0, nil, nil,Scanner会等待更多输入; - 解析成功时,
json.RawMessage会保存完整的JSON字节流,同时通过Decoder的内部指针可以知道解析了多少字节,再加上分隔符的长度(+1)就是需要前进的字节数; - 完美处理了嵌套JSON的情况,不会因为内部的大括号导致误分割。
内容的提问来源于stack exchange,提问作者Mark Eaton
相关产品推荐
相关产品推荐

