boost.json如何获取解析失败的位置

boost.json库提供了一个简便的 parse() 函数来解析JSON文本,只需要一个简单的调用即可,如下所示:

1
2
3
4
5
6
7
8
std::string json_text = ...;

try {
auto json_value = boost::json::parse(json_text);
}
catch (const boost::system::system_error&) {
//解析失败
}

这个函数能满足大部分场景的需求,但是假如我们想在解析失败的时候有更丰富的处理,例如显示解析失败位置附近的字符,它就无能为力了,因为解析失败时抛出的 boost::system::system_error 异常提供的信息有限,我们无法从异常信息中获取解析失败的位置。

为了达到这个目的,我们需要使用boost.json中更底层的 parser 类,调用它无异常版本的 write_some() 函数。如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
std::string json_text = ...;

boost::json::parser parser;
std::error_code error;
auto parsed_length = parser.write_some(json_text, error);

if (error) {
//解析失败,parsed_length即为解析失败的位置
}
else {
//解析成功,获取解析后的结果
auto json_value = parser.release();
}

write_some() 函数返回它读取过的字符数;如果出现解析失败,会通过 std::error_code 类型的参数返回错误而不会抛出异常,此时它的返回值就是解析失败的位置。

如果解析成功,需要调用 parser 的 release() 函数获取解析后的结果。此时 write_some() 的返回值一般等于输入的JSON文本的长度。需要注意的是,如果在一段完整的JSON文本后还存在其它字符, boost::json::parse() 函数会认为这是无效的JSON,从而解析失败;而 parser::write_some() 函数则会把完整的JSON解析完后,在其它剩余的字符串前返回。所以,如果想要与 boost::json::parser() 一致的行为,则需要再额外判断一下 parser::write_some() 的返回值是否与输入的JSON文本长度一致。