goahead处理json_jsoncpp按插入顺序排序和支持指定小数位数

本文介绍了如何通过修改jsoncpp源码实现按插入顺序输出json和自定义小数位数的功能。针对jsoncpp默认按字母排序输出的问题,作者通过记录插入索引并在输出时按索引排序解决了此问题。同时,对于小数精度,作者修改了源码,使得可以支持指定不超过6位的小数输出。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



jsoncpp是一个优秀的开源C++ json库,被广泛应用。在寻找C/C++ JSON库时,没有选择CJSON,而是选择了jsoncpp,主要考虑我应用程序是C++编写,如果使用CJSON的话,可能需要重新封装一层。

就我的应用而言,jsoncpp和CJSON都有一个共同问题:官方代码不支持指定小数位数。jsoncpp还有另一个问题:它默认按字母排序输出json。

一、按插入顺序输出json

我的应用需要按插入顺序输出json,所以不得不解决这个问题。

jsoncpp库采用map关联容器存储节点数据,map的特点是插入和查找时采用了红黑树算法,这决定了jsoncpp库并不是按插入顺序输出节点数据的。

但按该文章方法,总是实现不了按插入顺序输出。期间考虑了使用unordered_map、开源的fifo_map(https://github.com/nlohmann)来替换map,但总是有一些让人难懂的编译错误。所以最终放弃。

后面想了一个方法:插入数据时,记录插入索引;输出数据时,按插入索引输出。

首先,在class Value 中增加公有变量:

其中,m_precision初始化为17,m_insertIdx可不用初始化。

其次,找到插入数据的地方。在jsoncpp.cpp中搜索关键字:value_.map_->insert。有3个地方,以其中resolveReference为例,修改如下:

// @param key is not null-terminated.

Value& Value::resolveReference(char const* key, char const* cend)

{

JSON_ASSERT_MESSAGE(

type_ == nullValue || type_ == objectValue,

"in Json::Value::resolveReference(key, end): requires objectValue");

if (type_ == nullValue)

*this = Value(objectValue);

CZString actualKey(

key, static_cast(cend-key), CZString::duplicateOnCopy);

ObjectValues::iterator it = value_.map_->lower_bound(actualKey);

if (it != value_.map_->end() && (*it).first == actualKey)

return (*it).second;

#if 1// 记录节点插入的索引,用于按插入顺序输出 added by gyr 2019.06.02

const unsigned int idx = value_.map_->size();

#endif

ObjectValues::value_type defaultValue(actualKey, nullRef);

it = value_.map_->insert(it, defaultValue);

Value& value = (*it).second;

#if 1// 记录节点插入的索引,用于按插入顺序输出 added by gyr 2019.06.02

value.m_insertIdx = idx;

#endif

return value;

}

最后,找到输出数据的地方:Value::Members Value::getMemberNames()。修改如下:

Value::Members Value::getMemberNames() const {

JSON_ASSERT_MESSAGE(

type_ == nullValue || type_ == objectValue,

"in Json::Value::getMemberNames(), value must be objectValue");

if (type_ == nullValue)

return Value::Members();

Members members;

members.reserve(value_.map_->size());

ObjectValues::const_iterator it = value_.map_->begin();

ObjectValues::const_iterator itEnd = value_.map_->end();

#if 1 // 按插入顺序输出 added by gyr 2019.06.02

unsigned int idx = 0;

idx = 0;// 避免不使用时出现编译警告

#endif

for (; it != itEnd; ++it) {

#if 1 // 按插入顺序输出 added by gyr 2019.06.02

ObjectValues::const_iterator it1 = value_.map_->begin();

for (; it1 != itEnd; ++it1) {

if (it1->second.m_insertIdx == idx) {

members.push_back(std::string((*it1).first.data(),

(*it1).first.length()));

break;

}

}

idx++;

#else

members.push_back(std::string((*it).first.data(),

(*it).first.length()));

#endif

}

return members;

}

二、支持指定小数位数

对于实数类型,jsoncpp默认按%.17g进行输出,详见如下函数实现:

std::string valueToString(double value, bool useSpecialFloats, unsigned int precision)

该函数的调用者,precision固定为17。这也是上面新增公有成员m_precision初始化为17的缘故。

我的应用没超过6位小数,%.17g这种用法不是很明确,所以对上面函数进行了修改,如下:

std::string valueToString(double value, bool useSpecialFloats, unsigned int precision) {

// Allocate a buffer that is more than large enough to store the 16 digits of

// precision requested below.

char buffer[32];

int len = -1;

// added by gyr 2019.03.27

// precision默认17位小数,对于小于6位小数进行特殊处理

// printf %g用法不是很明确,所以对于超过6位小数的处理按原始方式

if (precision <= 6)

{

switch (precision)

{

case 0: sprintf(buffer, "%.0f", value); break;

case 1: sprintf(buffer, "%.1f", value); break;

case 2: sprintf(buffer, "%.2f", value); break;

case 3: sprintf(buffer, "%.3f", value); break;

case 4: sprintf(buffer, "%.4f", value); break;

case 5: sprintf(buffer, "%.5f", value); break;

case 6: sprintf(buffer, "%.6f", value); break;

}

return buffer;

}

char formatString[6];

sprintf(formatString, "%%.%dg", precision);

// Print into the buffer. We need not request the alternative representation

// that always has a decimal point because JSON doesn't distingish the

// concepts of reals and integers.

if (isfinite(value)) {

len = snprintf(buffer, sizeof(buffer), formatString, value);

} else {

// IEEE standard states that NaN values will not compare to themselves

if (value != value) {

len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "NaN" : "null");

} else if (value < 0) {

len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "-Infinity" : "-1e+9999");

} else {

len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "Infinity" : "1e+9999");

}

// For those, we do not need to call fixNumLoc, but it is fast.

}

assert(len >= 0);

fixNumericLocale(buffer, buffer + len);

return buffer;

}

三、代码下载

» 文章出处:

reille博客—http://velep.com

, 如果没有特别声明,文章均为reille博客原创作品

» 郑重声明:

原创作品未经允许不得转载,如需转载请联系reille#qq.com(#换成@)

分享到:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值