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;将描述任…

MySQL单主模式部署组复制集群

前言 本篇文章介绍MySQL8.0.27版本的组复制详细搭建过程&#xff0c;教你如何快速搭建一个三节点的单主模式组复制集群。 实际上&#xff0c;MySQL组复制是MySQL的一个插件 group_replication.so&#xff0c;组中的每个成员都需要配置并安装该插件&#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…

腾讯音乐面试题

Docker相关 Docker 是一个开源的应用容器平台&#xff0c;它允许开发者构建、打包、分发和运行任何应用——从简单的命令行工具到复杂的微服务架构。Docker 的核心概念主要包括&#xff1a; 容器 (Containers): Docker 容器是轻量级的、可执行的独立软件包&#xff0c;包含应用…

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…

Redis面试题42

人工智能对工作岗位和就业市场会有什么影响&#xff1f; 答&#xff1a;人工智能对工作岗位和就业市场将带来深远的影响。虽然一些工作可能会被自动化取代&#xff0c;但同时也将出现新的工作机会。以下是人工智能对工作岗位和就业市场的一些影响&#xff1a; 自动化工作&…

6. 尚硅谷大数据111门技术+42个项目

文章目录 第 1 章尚硅谷大数据全套技术第 2 章尚硅谷大数据全套项目 资料来源于网络&#xff0c;仅用于个人学习。 仅用于个人搜索使用。 第 1 章尚硅谷大数据全套技术 1.Java从入门到精通JDK版 链接&#xff1a;https://pan.baidu.com/s/1GAc610SYSMmZBuOX4DJ-lg 提取码&…

C++ //练习 4.17 说明前置递增运算符和后置递增运算符的区别。

C Primer&#xff08;第5版&#xff09; 练习 4.17 练习 4.17 说明前置递增运算符和后置递增运算符的区别。 环境&#xff1a;Linux Ubuntu&#xff08;云服务器&#xff09; 工具&#xff1a;vim 解释 前置递增运算符先对对象进行递增&#xff0c;然后取递增后的值赋值给左…

使用Dubbo实现微服务之间的高效通信

目录 一、RPC与Dubbo 二、Springboot整合Dubbo 服务端实现 消费端实现 一、RPC与Dubbo RPC&#xff08;Remote Procedure Call&#xff09;是指远程过程调用。 常见的RPC框架有Dubbo&#xff08;Alibaba &#xff09;、gRPC&#xff08;Google&#xff09;、Thrift&#…

Linux查看系统与资源

1、查看操作系统 # 查看操作系统版本&#xff1a; cat /etc/redhat-release2、查看CPU、内存 # 总核数 物理CPU个数 X 每颗物理CPU的核数 # 总逻辑CPU数 物理CPU个数 X 每颗物理CPU的核数 X 超线程数# 查看物理CPU的个数 cat /proc/cpuinfo | grep "physical id&…

解决icloud备份灰显的有效方法!

如果iCloud备份选项灰显&#xff0c;意味着你无法进行iCloud备份。以下是解决此问题的一些有效方法&#xff1a; 确保设备已连接到Wi-Fi网络&#xff1a;iCloud备份需要Wi-Fi网络连接。确保你的设备已连接到可靠的Wi-Fi网络。如果设备仍然连接到移动数据网络&#xff0c;iCloud…

高速接口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;可以把程序中的数据写到本地文件中…