如何跳过&x27;噪音';在JSON对象流中?
尝试获取以下代码以跳过JSON数据对象流中的解析错误噪声。基本上,我希望它跳过如何跳过&x27;噪音';在JSON对象流中?,json,parsing,go,io,Json,Parsing,Go,Io,尝试获取以下代码以跳过JSON数据对象流中的解析错误噪声。基本上,我希望它跳过错误:…行,继续下一条可解析记录 json.Decoder的索引集有限,因此不清楚如何将解码器的索引向前移动(比如一次移动一个字节)以越过噪声 io.Reader有一些方法可以跳到行尾(或者至少尝试一次跳过一个字符),但这样做不会(可以理解)影响json.Decoder的搜索状态 有没有干净的方法可以做到这一点 得到: 想要: 我认为这样做的“正确”方法是,由于流本身不是有效的JSON(即使没有错误,JSON文档也必
错误:…
行,继续下一条可解析记录
json.Decoder
的索引集有限,因此不清楚如何将解码器的索引向前移动(比如一次移动一个字节)以越过噪声
io.Reader
有一些方法可以跳到行尾(或者至少尝试一次跳过一个字符),但这样做不会(可以理解)影响json.Decoder
的搜索状态
有没有干净的方法可以做到这一点
得到:
想要:
我认为这样做的“正确”方法是,由于流本身不是有效的JSON(即使没有错误,JSON文档也必须有一个根条目,这是一系列无效的根对象),将预解析为单个有效的JSON文档,并分别解组。使用例如丢弃非JSON行,并将其他行正常地Unmarshal
逐行读取流
请参阅此处的工作示例:虽然不是很干净,但可以使用JSON解码器的
缓冲
方法访问底层读取器,该读取器仍应指向导致错误的字节,并在必要时将其包装在缓冲读取器中。然后,您可以读取单个字节,直到遇到一个有效的JSON开始对象字节{
,并且未读该字节(在任何实现中至少有1个字节可以未读),以将该字节推回到缓冲流中
然而
IMHO,正确的处理方法要求您接收一个JSON对象的JSON数组,允许您通过提供一个带有*事件
方法接收器的解组JSON
方法来处理表示事件
的每个JSON对象的手动标记化,但是如果您无法获得该方法,那么这并不重要r、 您需要修改提供的解决方案,使其在必要时工作,假设这是可能的。一种可能的补救方法是设置标志,并在检测到有效的JSON对象时取消设置:
objectDetected := false
i := 0
decodeLoop:
...
if b == '{' {
// If we already encountered an object and found ourselves here again,
// it's not really a valid JSON object.
if objectDetected {
break
}
objectDetected = true
br.UnreadByte()
...
fmt.Printf("%3d: %+v\n", i, ev)
objectDetected = false
} // decode loop end
}
为简单起见,我使用了一个字符串,但实际上数据是通过web服务流(不是我所有的),因此没有文档本身。我想解析可解析的数据并跳过任何垃圾不可解析的字节。每个记录都在一行上-因此跳到行的末尾(“\n”)将是可接受的解决方案。不管是字符串还是来自web服务。过程是一样的,扫描器仍然可以工作。请参阅我的编辑中的游乐场示例。我的评论与您关于这是无效JSON的声明有关(除了解析错误)。一个有效的JSON对象流对解码器是有效的。它可能会被一些解码器接受,但它不是有效的JSON,因此您不能合理地期望每个解码器都接受它。这就是为什么在尝试解码之前必须先将其预处理为不受干扰的有效JSON文档的原因。http-sse使用单个记录。它们不会开始解码带有“[”的JSON流。这实际上是我想要实现的:如果出现解析错误,请将搜索指针一次移动1个字节,直到读取有效记录。仅在“{”上搜索不一定有效,因为“噪声”可能包含“{”。因此,很好地使用
bufio.Reader
和Decoder.Buffered
来实现这一点。仅供参考:JSON“流”,虽然在游乐场示例中是静态的,但实际上它来自HTTP-SSE web服务(不在我们的控制范围内),需要实时处理"不可能。这是有道理的。我不确定您是否有权修改服务。您的流与Linux上的i3status程序类似,它输出一个包含版本信息的单个对象,然后是一个包含信息的无限/不完整的对象数组,这些对象包含要在状态栏上打印的信息。y和我们的情况是,在流打印感兴趣的对象之前,只有一个单独的对象。可以跳过流开头的已知异常项,但整个流中的异常要复杂一些。
1: {T:2017-11-02 16:00:00 -0400 -0400 Desc:window opened}
2: {T:2017-11-02 16:30:00 -0400 -0400 Desc:window closed}
3: {T:2017-11-02 16:41:34 -0400 -0400 Desc:front door opened}
parse error: %s invalid character 'E' looking for beginning of value
1: {T:2017-11-02 16:00:00 -0400 -0400 Desc:window opened}
2: {T:2017-11-02 16:30:00 -0400 -0400 Desc:window closed}
3: {T:2017-11-02 16:41:34 -0400 -0400 Desc:front door opened}
4: {T:2017-11-02 16:41:40 -0400 -0400 Desc:front door closed}
...
decodeLoop:
for decodeStream.More() {
i++
var ev event
if err := decodeStream.Decode(&ev); err != nil {
r := decodeStream.Buffered()
br, ok := r.(*bufio.Reader)
if !ok {
br = bufio.NewReader(r)
}
for {
b, err := br.ReadByte()
if err != nil {
// Whether EOF or not, there's nothing left to do except
// break the loop to trigger the "parse error" statement.
break
}
// A (potentially) valid JSON object was found;
// create a new decoder associated with the same decodeStream var
// using the new buffered reader and continue decoding.
if b == '{' {
br.UnreadByte()
decodeStream = json.NewDecoder(br)
continue decodeLoop
}
}
fmt.Println("parse error: %s", err)
break
}
...
objectDetected := false
i := 0
decodeLoop:
...
if b == '{' {
// If we already encountered an object and found ourselves here again,
// it's not really a valid JSON object.
if objectDetected {
break
}
objectDetected = true
br.UnreadByte()
...
fmt.Printf("%3d: %+v\n", i, ev)
objectDetected = false
} // decode loop end
}