【C++】使用 nlohmann 解析 json 文件

更正

通过数组的方式访问某个key也是会抛出异常的,只是它不能准确定位异常的位置,但是通过at方法是可以定位到具体异常的(如果访问的key不存在)。

引言

nlohman json GitHub - nlohmann/json: JSON for Modern C++ 是一个为现代C++(C++11)设计的JSON解析库,主要特点是

  • 易于集成,仅需一个头文件,无需安装依赖

  • 易于使用,可以和STL无缝对接,使用体验近似python中的json

常见用法

1. json初始化

1.1 从文件初始化
std::ifstream in_file("test.json");
nlohmann::json doc;
if (!in_file.is_open()) {
    exit(1);
}
in_file >> doc;
in_file.close();
1.2 从字符串初始化

方式1

nlohmann::json doc = R"({"key1":"value1", "key2":[1,2,3]})"_json;
// nlohmann::json doc = "{\"key1\":\"value1\", \"key2\":[1,2,3]}"_json; // 此种情况下需要对json字符串中的双引号进行转义
  • R表示json字符串中的特殊字符均按照字符本身进行解析,而不需要进行转义,如双引号、反斜杠等字符

  • _json结尾表示其是一个json对象

方式2

std::string info = R"({"key1":"value1", "key2":[1,2,3]})";
nlohmann::json doc = nlohmann::json::parse(info);
  • 调用json::parse方法,通过传入一个字符串进行构造,此时不以 _json结尾
1.3 直接构造json对象

方式1

// {"key1":"value1","key2":[1,2,3],"key3":{"key":"val"}}
nlohmann::json doc = {{"key1", "value1"}, {"key2", {1,2,3}}, {"key3", {{"key", "val"}}}};
  • 最外层的花括号表示一个json object

  • 里面的每一对花括号的第一个元素为key,第二个元素为value,用’,'分割

  • 注意:单对花括号包裹的是array,两对花括号包裹的才是json object,如:

    • {1, 2}是一个array,即[1, 2]

    • {{1, 2}}是一个object,即{1:2},key为1,value为2

方式2

// {"app":"wechat","array":[1,2,4],"obj":{"age":15,"name":"zs","sex":"m"}}
nlohmann::json doc;
doc["app"] = "wechat";  // 添加一个k-v,若key存在则覆盖value
doc["array"] = {1,2,3}; // 添加一个数组
doc["array"].emplace_back(4); // 数组添加一个元素
doc["array"].erase(2); // 删除下标为2的元素
doc["obj"] = {{"name", "zs"}, {"age", 15}}; // 添加一个object
doc["obj"].push_back({"sex", "m"}); // 通过push方法添加一个k-v,若key存在则忽略,不会覆盖value
doc.push_back({"app", "qq"}); // key存在,故忽略

2. json访问

json展开如下:

{
  "retCode": 0,
  "retMSg": "成功",
  "data": [
    {
      "name": "李雷",
      "id": "001",
      "score": {
        "Chinese": 80,
        "Math": 95
      },
      "schoolInfo": [
        {
          "School_name": "清华"
        },
        {
          "School_name": "北大"
        }
      ]
    },
    {
      "name": "韩梅梅",
      "id": "002",
      "score": {
        "Chinese": 90,
        "Math": 80
      },
      "schoolInfo": [
        {
          "School_name": "清华"
        },
        {
          "School_name": "北大"
        }
      ]
    }
  ]
}

循环遍历

std::string info = R"({"retCode":0,"retMSg":"成功","data":[{"name":"李雷","id":"001","score":{"Chinese":80,"Math":95},"schoolInfo":[{"School_name":"清华"},{"School_name":"北大"}]},{"name":"韩梅梅","id":"002","score":{"Chinese":90,"Math":80},"schoolInfo":[{"School_name":"清华"},{"School_name":"北大"}]}]})";
try {
    nlohmann::json doc = nlohmann::json::parse(info);
} catch (std::expection& e){
    // json转化失败会抛出异常,如json格式错误等
    std::cout << e.what() << std::endl;
}
// 循环遍历
for (auto& item : doc.items()) {
    const std::string& key = item.key();
    auto& value = item.value(); // 用引用减少拷贝
    if (value.is_number()) {
        auto val = value.get<int>(); // 推导为int,如果是浮点型,转化为int则只保留整数部分
        // int val = value;          // 强转为int型
        // auto val = value.get<uint32_t>();
        // auto val = value.get<double>();
    } else if (value.is_string()) {
        const std::string& str = value;
        // std::string str = value;
    } else if (value.is_array()) { // value是一个数组
        int len = value.size();
        for (int i = 0; i < len; ++i) {
            if (value[i].is_object()) {
                ;
            } else if (value[i].is_string()) {
                ;
            }
        }
    } else if (value.is_object()) { // value是一个json
        for(auto& item_2 : value.items()) {
            ;                       // 类似处理
        }
    } else if (value.is_boolean()) {
        bool b = value; // 或者直接用value进行传参,他会隐式转换为bool型
    }
}

指定key遍历

std::string info = R"({"retCode":0,"retMSg":"成功","data":[{"name":"李雷","id":"001","score":{"Chinese":80,"Math":95},"schoolInfo":[{"School_name":"清华"},{"School_name":"北大"}]},{"name":"韩梅梅","id":"002","score":{"Chinese":90,"Math":80},"schoolInfo":[{"School_name":"清华"},{"School_name":"北大"}]}]})";
nlohmann::json doc = nlohmann::json::parse(info);
if (doc.contains("retCode") && doc["retCode"].is_number()) {
    int retCode = doc["retCode"];
}
if (doc.contains("data") && doc["data"].is_array()) {
    nlohmann::json& doc_arr = doc["data"];
    int len = doc_arr.size();
} else if (doc.contains("data") && doc["data"].is_object()) {
    nlohmann::json& doc_json = doc["data"];
}

访问key的几种方式

// 1. 直接通过key访问
std::string retMsg = doc["retMSg"];  // key不存在会出core(所以要判断key是否存在),类型转换失败也会core
// 2. 通过at方法访问
std::string retMsg = doc.at("retMSg"); // 同上,不同点在于at方法可以抛出异常(如果key不存在)
  • 两种方式正常情况下返回的结果都是nlohmann::json对象,并且可以隐式转化为string以及各种基本类型

  • 为了避免上述可能出现的问题,直接访问key对应的value时,尽量按如下方式编写程序:

    1. 先判断key是否存在(contains)

    2. 再判断key的类型,key类型相关的判断方法如下:

    方法含义
    is_number是否为数字(int、uint32_t、uint64_t、double等)
    is_boolean是否为bool
    is_string是否为字符串
    is_array是否为数组
    is_object是否为json
  • 当然也可以通过捕获异常的方式来达到避免程序出错的目的,注意由于doc[“retMSg”]这种访问方式不能抛出异常,应该使用doc.at(“retMSg”)这种方式来访问。

3. json序列化

json序列化就是将json对象序列化成json格式的字符串或者存储到文本文件

序列化为json字符串

string str = doc.dump();

保存为json文件

nlohmann::json doc;

doc["app"] = "wechat";
doc["age"] = 17;

std::ofstream out_file("test.json");
out_file << doc;
  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值