C++ JSON解析

JSON解析

    • JSONCPP
      • C++实现JSON解析器


JSONCPP

JSONCPP源码链接:https://github.com/open-source-parsers/jsoncpp

  1. JSOCPP源码下载以后,首先复制一份include文件夹下的json文件夹,头文件留着后续备用。
    在这里插入图片描述
  2. 使用Cmake生成项目。在IDE中编译jsoncpp_lib,可以在项目的lib/Debug文件夹下找到jsoncpp.lib,在bin/Debug/文件夹下找到jsoncpp.dll。将头文件和动态链接库文件,放入项目中即可使用。
    在这里插入图片描述
    在这里插入图片描述
    jsoncpp库中的类被定义到了一个Json命名空间中,使用时最好先声明这个命名空间。

使用jsoncpp库解析json格式的数据,三个类:

  • Value 类:将json支持的数据类型进行了包装,最终得到一个Value类型。
  • FastWriter类:将Value对象中的数据序列化为字符串。
  • Reader类:反序列化,将json字符串解析成Value类型。

C++实现JSON解析器

#pragma once
#include<string>
#include<map>
#include<vector>
#include<sstream>
#include<iostream>namespace Cliu {namespace json {class JsonElement;using JsonObject = std::map<std::string, JsonElement*>;using JsonArray = std::vector<JsonElement*>;class JsonElement {public:enum class Type {JSON_OBJECT,JSON_ARRAY,JSON_STRING,JSON_NUMBER,JSON_BOOL,JSON_NULL};union Value {JsonObject* value_object;JsonArray* value_array;std::string* value_string;float value_number;bool value_bool;};JsonElement() : JsonElement(Type::JSON_NULL) {}JsonElement(const Type& type) : type_(type) {switch (type) {case Type::JSON_OBJECT:value_.value_object = new std::map<std::string, JsonElement*>();break;case Type::JSON_ARRAY:value_.value_array = new std::vector<JsonElement*>();break;case Type::JSON_STRING:value_.value_string = new std::string("");break;case Type::JSON_NUMBER:value_.value_number = 0;break;case Type::JSON_BOOL:value_.value_bool = false;break;case Type::JSON_NULL:break;default:break;}};JsonElement(JsonObject* object) : type_(Type::JSON_OBJECT) { value(object); }JsonElement(JsonArray* array) : type_(Type::JSON_ARRAY) { value(array); }JsonElement(std::string* str) : type_(Type::JSON_STRING) { value(str); }JsonElement(float number) : type_(Type::JSON_NUMBER) { value(number); }JsonElement(bool val) : type_(Type::JSON_BOOL) { value(val); }~JsonElement() {if (type_ == Type::JSON_OBJECT) {JsonObject* object = value_.value_object;for (auto& a : *object) {delete a.second;}delete object;}else if (type_ == Type::JSON_ARRAY) {JsonArray* array = value_.value_array;for (auto& item : *array) {delete item;}delete array;}else if (type_ == Type::JSON_STRING) {std::string* val = value_.value_string;delete val;}}Type type() { return type_; }void value(JsonObject* value) {type_ = Type::JSON_OBJECT;value_.value_object = value;}void value(JsonArray* value) {type_ = Type::JSON_ARRAY;value_.value_array = value;}void value(std::string* value) {type_ = Type::JSON_STRING;value_.value_string = value;}void value(float value) {type_ = Type::JSON_NUMBER;value_.value_number = value;}void value(bool value) {type_ = Type::JSON_BOOL;value_.value_bool = value;}JsonObject* AsObject() {if (type_ == Type::JSON_OBJECT) {return value_.value_object;}else {Error("Type of JsonElement isn't JsonObject!");return nullptr;}}JsonArray* AsArray() {if (type_ == Type::JSON_ARRAY) {return value_.value_array;}else {Error("Type of JsonElement isn't JsonArray!");return nullptr;}}std::string* AsString() {if (type_ == Type::JSON_STRING) {return value_.value_string;}else {Error("Type of JsonElement isn't String!");return nullptr;}}float AsNumber() {if (type_ == Type::JSON_NUMBER) {return value_.value_number;}else {Error("Type of JsonElement isn't Number!");return 0.0f;}}bool AsBoolean() {if (type_ == Type::JSON_BOOL) {return value_.value_bool;}else {Error("Type of JsonElement isn't Boolean!");return false;}}std::string Dumps() {std::stringstream ss;switch (type_) {case Type::JSON_OBJECT:ss << *(value_.value_object);break;case Type::JSON_ARRAY:ss << *(value_.value_array);break;case Type::JSON_STRING:ss << '\"' << *(value_.value_string) << '\"';break;case Type::JSON_NUMBER:ss << value_.value_number;break;case Type::JSON_BOOL:ss << (value_.value_bool == true ? "true" : "false");break;case Type::JSON_NULL:ss << "null";break;default:break;}return ss.str();}friend std::ostream& operator<<(std::ostream& os, const JsonObject& object) {os << "{";for (auto iter = object.begin(); iter != object.end(); iter++) {os << '\"' << iter->first << '\"' << ": " << iter->second->Dumps();if (iter != --object.end()) {os << ", ";}}os << "}";return os;}friend std::ostream& operator<<(std::ostream& os, const JsonArray& array) {os << "[";for (size_t i = 0; i < array.size(); i++) {os << array[i]->Dumps();if (i != array.size() - 1) {os << ", ";}}os << "]";return os;}private:Type type_;Value value_;};} // namespace json} // namespace Cliu
#pragma once
#include<string>
#include"Error.h"
#include<iostream>namespace Cliu {namespace json {class Scanner {
public:Scanner(const std::string& source) : source_(source), current_(0) {}Scanner(std::string&& source) : source_(std::move(source)), current_(0) {}enum class JsonTokenType{BEGIN_OBJECT, ///< {END_OBJECT, ///< }VALUE_SEPARATOR, ///< , 逗号NAME_SEPARATOR, ///< : 冒号VALUE_STRING, ///< "string"VALUE_NUMBER, ///< 1,2,2e10LITERAL_TRUE, ///< trueLITERAL_FALSE,///< falseLITERAL_NULL, ///< nullBEGIN_ARRAY, ///< [ 数组左括号END_ARRAY, ///< ] 数组右括号END_OF_SOURCE, ///< EOFERROR };JsonTokenType Scan(); // 扫描下一个,返回下一个token的typevoid Rollback();friend std::ostream& operator<<(std::ostream& os, const JsonTokenType& type) {switch (type) {case JsonTokenType::BEGIN_ARRAY:os << "[";break;case JsonTokenType::END_ARRAY:os << "]";break;case JsonTokenType::BEGIN_OBJECT:os << "{";break;case JsonTokenType::END_OBJECT:os << "}";break;case JsonTokenType::NAME_SEPARATOR:os << ":";break;case JsonTokenType::VALUE_SEPARATOR:os << ",";break;case JsonTokenType::VALUE_NUMBER:os << "number";break;case JsonTokenType::VALUE_STRING:os << "string";break;case JsonTokenType::LITERAL_TRUE:os << "true";break;case JsonTokenType::LITERAL_FALSE:os << "false";break;case JsonTokenType::LITERAL_NULL:os << "null";break;case JsonTokenType::END_OF_SOURCE:os << "EOF";break;default:break;}return os;}float GetNumberValue() { return value_number_; };const std::string& GetStringValue() { return value_string_; };private:bool IsAtEnd();char Advance();void ScanTrue();void ScanFalse();void ScanNull();void ScanString();void ScanNumber();char Peek();char PeekNext();bool IsDigit(char c);private:std::string source_; ///< json sourcesize_t current_;      ///< current pos of processing charactersize_t prev_pos_;  ///< previous handling pos;float value_number_;        ///< number valuestd::string value_string_;  ///< string value};// end of class Scanner} // namespace json} // namespace Cliu
#include "Scanner.h"namespace Cliu {namespace json {bool Scanner::IsAtEnd() {return current_ >= source_.size();
}char Scanner::Advance() {return source_[current_++];
}void Scanner::Rollback() { current_ = prev_pos_; }bool Scanner::IsDigit(char c) { return c >= '0' && c <= '9'; }char Scanner::Peek() { // 获取下一个if (IsAtEnd()) return '\0';return source_[current_];
}char Scanner::PeekNext() { // 要确保下一个值是存在的if (current_ + 1 >= source_.size()) return '\0';return source_[current_ + 1];
}void Scanner::ScanTrue() { // 判断是否是trueif (source_.compare(current_, 3, "rue") == 0) {current_ += 3;}else {Error("Scan `true` error");}
}void Scanner::ScanFalse() {if (source_.compare(current_, 4, "alse") == 0) {current_ += 4;}else {Error("Scan `false` error");}
}void Scanner::ScanNull() {if (source_.compare(current_, 3, "ull") == 0) {current_ += 3;}else {Error("Scan `null` error");}
}void Scanner::ScanString() {size_t pos = current_;while (Peek() != '\"' && !IsAtEnd()) {Advance();// 再走一步 //没有考虑转义字符}if (IsAtEnd()) {Error("invalid string: missing closing quote");}Advance();value_string_ = source_.substr(pos, current_ - pos - 1);
}void Scanner::ScanNumber() {size_t pos = current_ - 1;while (IsDigit(Peek())) {Advance();}// fractional partif (Peek() == '.' && IsDigit(PeekNext())) {Advance();while (IsDigit(Peek())) {Advance();}}value_number_ = std::atof(source_.substr(pos, current_ - pos).c_str());
}Scanner::JsonTokenType Scanner::Scan()
{// 判断是否扫描完毕if (IsAtEnd()) {return JsonTokenType::END_OF_SOURCE; // 返回扫描完毕标识符}prev_pos_ = current_;char c = Advance(); // 获取下一个字符switch (c){case '[':return JsonTokenType::BEGIN_ARRAY;case ']':return JsonTokenType::END_ARRAY;case '{':return JsonTokenType::BEGIN_OBJECT;case '}':return JsonTokenType::END_OBJECT;case ':':return JsonTokenType::NAME_SEPARATOR;case ',':return JsonTokenType::VALUE_SEPARATOR;case 't':ScanTrue();return JsonTokenType::LITERAL_TRUE;case 'f':ScanFalse();return JsonTokenType::LITERAL_FALSE;case 'n':ScanNull();return JsonTokenType::LITERAL_NULL;case '-':case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':ScanNumber();return JsonTokenType::VALUE_NUMBER;case '\"':ScanString();return JsonTokenType::VALUE_STRING;case ' ':case '\r':case '\n':case '\t':return Scan();default:// errorstd::string message = "Unsupported Token: ";message += c;Error(std::string(message));return JsonTokenType::ERROR;}return JsonTokenType();
}} // namespace json} // namespace Cliu
#pragma once
#include"Scanner.h"
#include"JsonElement.h"namespace Cliu {namespace json {class Parser {using JsonTokenType = Scanner::JsonTokenType;public:JsonElement* Parse();Parser(const Scanner& scanner) : scanner_(scanner) {}private:JsonObject* ParseObject();JsonArray* ParseArray();private:Scanner scanner_;};} // namespace json} // namespace Cliu
#include"Parser.h"namespace Cliu {namespace json {JsonElement* Parser::Parse() {JsonElement* element = new JsonElement();JsonTokenType token_type_ = scanner_.Scan();if (token_type_ != JsonTokenType::END_OF_SOURCE) {switch (token_type_) {case JsonTokenType::BEGIN_OBJECT: {JsonObject* object = ParseObject();element->value(object);break;}case JsonTokenType::BEGIN_ARRAY: {JsonArray* array = ParseArray();element->value(array);break;}case JsonTokenType::VALUE_STRING: {std::string* val = new std::string(scanner_.GetStringValue());element->value(val);break;}case JsonTokenType::VALUE_NUMBER: {element->value(scanner_.GetNumberValue());break;}case JsonTokenType::LITERAL_TRUE: {element->value(true);break;}case JsonTokenType::LITERAL_FALSE: {element->value(false);break;}case JsonTokenType::LITERAL_NULL: {break;}default:break;}}return element;}JsonObject* Parser::ParseObject() {JsonObject* res = new JsonObject();JsonTokenType next = scanner_.Scan();if (next == JsonTokenType::END_OBJECT) { //判断是否为空对象return res;}scanner_.Rollback();// 回退一步while (true) {next = scanner_.Scan();if (next != JsonTokenType::VALUE_STRING) {Error("Key must be string!");}std::string key = scanner_.GetStringValue();next = scanner_.Scan();if (next != JsonTokenType::NAME_SEPARATOR) {Error("Expected ':' in object!");}(*res)[key] = Parse();next = scanner_.Scan();if (next == JsonTokenType::END_OBJECT) {break;}if (next != JsonTokenType::VALUE_SEPARATOR) {Error("Expected ',' in object!");}}return res;}JsonArray* Parser::ParseArray() {JsonArray* res = new JsonArray();JsonTokenType next = scanner_.Scan();if (next == JsonTokenType::END_ARRAY) {return res;}scanner_.Rollback();while (true) {res->push_back(Parse());next = scanner_.Scan();if (next == JsonTokenType::END_ARRAY) {break;}if (next != JsonTokenType::VALUE_SEPARATOR) {Error("Expected ',' in array!");}}return res;}} // namespace json} // namespace Cliu

参考列表
https://subingwen.cn/cpp/jsoncpp/?highlight=json
https://blog.csdn.net/qq_43142808/article/details/115654942
https://zhuanlan.zhihu.com/p/476271291

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/670350.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Nicn的刷题日常】之打印整数二进制的奇数位和偶数位

目录 1.题目描述 2.解题思路 3.解题 1.题目描述 获取一个整数二进制序列中所有的偶数位和奇数位&#xff0c;分别打印出二进制序列 2.解题思路 1. 提取所有的奇数位&#xff0c;如果该位是1&#xff0c;输出1&#xff0c;是0则输出0 2. 以同样的方式提取偶数位置检测n…

CGAL-3D 凸包算法

3D 凸包算法 一、概述二、静态凸包构造1. Traits 特征类2. 极端点3. 半空间相交4. 凸性检验 三、动态凸包构造四、性能 一、概述 一个点集 S∈R3 是凸的&#xff0c;如果对于任意两点 p 和 q 在集合中&#xff0c;具有端点的线段 p 和 q 包含在 S。集合的凸包 P 包含点集 S 的最…

GADM 4.1 全球国家行政区划下载

扫描文末二维码&#xff0c;关注微信公众号&#xff1a;ThsPool 后台回复g004&#xff0c;领取最新 GADM 4.1 全球国家行政区划 GADM概述 GADM&#xff0c;全称 Database of Global Administrative Areas&#xff0c;是一个开放获取的全球行政区划数据库&#xff0c;包含各国、…

APIfox编排自动化测试场景(一)

测试场景用于将多个接口请求与实际可能发生的一些特殊情况&#xff08;如条件判断、循环&#xff09;有序的组合在一起&#xff0c;来模拟一个真实业务流程&#xff0c;组成自动化测试单元。 新建目录 / 测试场景​ 打开 Apifox 后点击左侧菜单栏中的“自动化测试”&#xff…

基于Vue的移动端UI框架整理

一、Vant 官方地址&#xff1a;https://youzan.github.io/vant/#/zh-CN/ 简介&#xff1a;有赞公司开发。 特性&#xff1a;60 高质量组件、90% 单元测试覆盖率、完善的中英文文档和示例、支持按需引入、支持主题定制、支持国际化、支持 TS、支持 SSR。 特别说明&#xff1…

机器学习---概率图模型(隐马尔可夫模型、马尔可夫随机场、条件随机场)

1. 隐马尔可夫模型 机器学习最重要的任务是根据已观察到的证据&#xff08;例如训练样本&#xff09;对感兴趣的未知变量&#xff08;例如类别标 记&#xff09;进行估计和推测。概率模型&#xff08;probabilistic model&#xff09;提供了一种描述框架&#xff0c;将描述任…

R语言阈值效应函数cut.tab2.0版发布(支持线性回归、逻辑回归、cox回归,自定义拐点)

阈值效应和饱和效应是剂量-反应关系中常见的两种现象。阈值效应是指当某种物质的剂量达到一定高度时&#xff0c;才会对生物体产生影响&#xff0c;而低于这个剂量则不会产生影响。饱和效应是指当某种物质的剂量达到一定高度后&#xff0c;其影响不再随剂量的增加而增加&#x…

编译DuiLib库遇到的变量定义位置问题

C89 规定&#xff0c;所有局部变量都必须定义在函数开头&#xff0c;在定义好变量之前不能有其他的执行语句&#xff1b; C99 标准取消这这条限制&#xff0c;但是 VC/VS 对 C99 的支持不是很积极&#xff1b; C99 是 C89 的升级版&#xff1b; 如图是修改之后的代码&#xff1…

AI专题:海外科技巨头指引,AI主线逻辑依旧坚挺

今天分享的是AI 系列深度研究报告&#xff1a;《AI专题&#xff1a;海外科技巨头指引&#xff0c;AI主线逻辑依旧坚挺》。 &#xff08;报告出品方&#xff1a;华西证券&#xff09; 报告共计&#xff1a;54页 本周热点:海外科技巨头指引&#xff0c;AI主线逻辑依旧坚挺 硬件…

介绍docker

一&#xff1a;介绍docker&#xff1a; Docker 并没有单独的图形界面&#xff0c;它主要通过命令行来进行管理和操作 1、 docker ps&#xff1a;显示正在运行的容器。 docker images&#xff1a;显示本地的镜像。 docker run&#xff1a;创建并启动一个新容器。 docker stop&a…

高速接口PCB布局指南(二)通用高速信号布线

高速接口PCB布局指南&#xff08;二&#xff09;通用高速信号布线 1.PCB材料编织2.高速信号布线长度3.高速信号布线长度匹配4.高速信号参考平面 tips&#xff1a;资料主要来自网络&#xff0c;仅供学习使用。 1.PCB材料编织 在常见的 PCB 材料上为差分信号布线时&#xff0c;…

Java笔记 --- 六、IO流

六、IO流 概述 分类 纯文本文件&#xff1a;Windows自带的记事本打开能读懂的 eg&#xff1a;txt文件&#xff0c;md文件&#xff0c;xml文件&#xff0c;lrc文件 IO流体系 字节流 FileOutputStream 操作本地文件的字节输出流&#xff0c;可以把程序中的数据写到本地文件中…

如何进行游戏服务器的负载均衡和扩展性设计?

​在进行游戏服务器的负载均衡和扩展性设计时&#xff0c;需要考虑多个方面&#xff0c;以确保服务器的稳定性和可扩展性。以下是一些关键的步骤和考虑因素&#xff1a; 负载均衡的需求分析 在进行负载均衡设计之前&#xff0c;需要深入了解游戏服务器的负载特性和需求。这包括…

2024.2.5 vscode连不上虚拟机,始终waiting for server log

昨天还好好的&#xff0c;吃着火锅&#xff0c;做着毕设&#xff0c;突然就被vscode给劫了。 起初&#xff0c;哥们跟着网上教程有模有样地删除了安装包缓存&#xff0c;还删除了.vscode-server&#xff0c;发现没卵用&#xff0c;之前都是搜那个弹窗报错。 后来发现原来是vsco…

mac检查CPU温度和风扇速度软件:Macs Fan Control Pro 1.5.17中文版

Macs Fan Control Pro for Mac是一款专业的电脑风扇控制工具&#xff0c;旨在帮助Mac用户有效控制电脑的风扇速度&#xff0c;提高电脑的运行效率和稳定性。 软件下载&#xff1a;Macs Fan Control Pro 1.5.17中文版 该软件支持多种风扇控制模式和预设方案&#xff0c;用户可以…

三层交换组网实验(思科)

华为设备参考&#xff1a;三层交换组网实验&#xff08;华为&#xff09; 一&#xff0c;技术简介 三层交换技术的出现&#xff0c;解决子网必须依赖路由器进行管理的问题&#xff0c;解决传统路由器低速、复杂所造成的网络瓶颈问题。一个具有三层交换功能的设备可简单理解为…

Zephyr NRF7002 实现AppleJuice

BLE的基础知识 ble的信道和BR/EDR的信道是完全不一样的。但是范围是相同的&#xff0c;差不多也都是2.4Ghz的频道。可以简单理解为空中有40个信道0~39信道。两个设备在相同的信道里面可以进行相互通信。 而这些信道SIG又重新编号&#xff1a; 这个编号就是把37 38 39。 3个信道…

杨中科 配置系统

1、配置系统入门 说明 1、传统Web.config配置的缺点&#xff0c;之前DI讲到过 2、为了兼容&#xff0c;仍然可以使用Web.config和ConfigurationManager类&#xff0c;但不推荐。 3、.NET 中的配置系统支持丰富的配置源&#xff0c;包括文件(json、xml、ini等)、注册表、环境变…

OpenCV/C++:点线面相关计算(二)

接续&#xff0c;继续更新 OpenCV/C:点线面相关计算_线面相交的点 代码计算-CSDN博客文章浏览阅读1.6k次&#xff0c;点赞2次&#xff0c;收藏12次。OpenCV处理点线面的常用操作_线面相交的点 代码计算https://blog.csdn.net/cd_yourheart/article/details/125626239 目录 1、…

Unity_修改天空球

Unity_修改天空球 Unity循序渐进的深入会发现可以改变的其实很多&#xff0c;剖开代码逻辑&#xff0c;可视化的表现对于吸引客户的眼球是很重要的。尤其对于知之甚少的客户&#xff0c;代码一般很难说服客户&#xff0c;然表现确很容易。 非代码色彩通才&#xff0c;持续学习…