C++ JSON解析

news2024/11/15 23:23:53

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,2e10

		LITERAL_TRUE, ///< true
		LITERAL_FALSE,///< false
		LITERAL_NULL, ///< null

		BEGIN_ARRAY, ///< [ 数组左括号
		END_ARRAY, ///< ] 数组右括号

		END_OF_SOURCE, ///< EOF

        ERROR 

	};

	JsonTokenType Scan(); // 扫描下一个,返回下一个token的type

    void 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 source
	size_t current_;      ///< current pos of processing character
    size_t prev_pos_;  ///< previous handling pos;

	float value_number_;        ///< number value
	std::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() { // 判断是否是true
    if (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 part
    if (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:
        // error
        std::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.coloradmin.cn/o/1438596.html

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

相关文章

使用SpringMVC实现功能

目录 一、计算器 1、前端页面 2、服务器处理请求 3、效果 二、用户登陆系统 1、前端页面 &#xff08;1&#xff09;登陆页面 &#xff08;2&#xff09;欢迎页面 2、前端页面发送请求--服务器处理请求 3、效果 三、留言板 1、前端页面 2、前端页面发送请求 &…

Spring核心基础:全面总结Spring中提供的那些基础工具类!

内容概要 Spring Framework 提供了众多实用的工具类&#xff0c;这些工具类在简化开发流程、提升代码质量和维护性方面发挥了重要作用&#xff0c;以下是部分关键工具类的总结及其使用场景&#xff1a; StringUtils&#xff1a;不仅提供了基础的字符串操作&#xff0c;如拼接…

Leetcode刷题笔记题解(C++):64. 最小路径和

思路一&#xff1a;dfs深度优先搜索&#xff0c;然后取最小路径值&#xff0c;但是时间消耗较大&#xff0c;时间复杂度可能不满足&#xff0c;代码如下&#xff1a; class Solution { public:int res 1000000;int rows,cols;int minPathSum(vector<vector<int>>…

跳过mysql5.7密码并重置密码 shell脚本

脚本 目前只是验证了5.7 版本是可以的&#xff0c;8.多的还需要验证 以下是一个简单的Shell脚本&#xff0c;用于跳过MySQL密码设置并重置密码&#xff1a; #!/bin/bash yum install psmisc -y# 停止MySQL服务 sudo service mysqld stop# 跳过密码验证 sudo mysqld --skip-g…

SpringBoot集成Swagger2的增强版Knife4j

1. 背景 作为SpringBoot集成中间件其中的一篇文章吧&#xff0c;既然打算出这么一个系列了&#xff0c;争取做到虽小却全&#xff0c;又精又美的一个系列吧。 Swagger应该都有接触吧&#xff0c;knife4j是Swagger2的增强版&#xff0c;更加友好的操作页面&#xff0c;更多强大…

瑞_力扣LeetCode_二叉树相关题

文章目录 说明题目 144. 二叉树的前序遍历题解 题目 94. 二叉树的中序遍历题解 题目 145. 二叉树的后序遍历题解 题目 105. 从前序与中序遍历序列构造二叉树题解 题目 106. 从中序与后序遍历序列构造二叉树题解 &#x1f64a; 前言&#xff1a;本文章为瑞_系列专栏之《刷题》的…

NAT几种模式的简介

静态NAT&#xff08;不转换端口号&#xff09;也叫一对一NAT&#xff0c;固定对应关系&#xff1a;内部网络服务器对外提供服务。 动态NAT之NO-PAT&#xff08;不转换端口号&#xff09;&#xff0c;一对多。 动态NAT之NAPT&#xff08;转换端口号&#xff09;&#xff0c;一对…

《Git 简易速速上手小册》第2章:理解版本控制(2024 最新版)

文章目录 2.1 本地仓库与版本历史2.1.1 基础知识讲解2.1.2 重点案例&#xff1a;回滚错误提交2.1.3 拓展案例 1&#xff1a;利用 git bisect 查找引入 bug 的提交2.1.4 拓展案例 2&#xff1a;合并提交历史 2.2 远程仓库的使用2.2.1 基础知识讲解2.2.2 重点案例&#xff1a;在 …

2024年龙年春节热点!过年期间想股票开户可以吗?怎么找到低佣金开户渠道?

股票投资技巧可以帮助投资者在股票市场中进行更明智的决策和更有效的操作。以下是一些常见的股票投资技巧&#xff1a; 研究和分析&#xff1a;在购买股票之前&#xff0c;投资者应该进行充分的研究和分析。这包括了解公司的基本面&#xff0c;如财务状况、业务模式和竞争优势等…

modelsim仿真使用到vivado的IP,该如何使用!

modelsim仿真时&#xff0c;如果使用到了vivado的IP就会报错&#xff0c;本次就告诉大家如何将vivado的IP添加到modelsim中直接仿真。 一、生成ini文件以及IP打包 打开vivado&#xff0c;点击上方的Tools-->Compile Simulation Libraries得到如下界面 simulator&#xff1…

【Linux】基于管道进行进程间通信

进程间通信 一、初识进程间通信1. 进程间通信概念2. 进程间通信分类 二、管道1. 管道概念2. 管道原理3. 匿名管道4. 匿名管道系统接口5. 管道的特性和情况6. 匿名管道的应用&#xff08;1&#xff09;命令行&#xff08;2&#xff09;进程池 7. 命名管道&#xff08;1&#xff…

机器人运动学林沛群——变换矩阵

对于仅有移动&#xff0c;由上图可知&#xff1a; A P B P A P B o r g ^AP^BP^AP_{B org} APBPAPBorg​ 对于仅有转动&#xff0c;可得&#xff1a; A P B A R B P ^AP^A_BR^BP APBA​RBP 将转动与移动混合后&#xff0c;可得&#xff1a; 一个例子 在向量中&#xff…

电力负荷预测 | 电力系统负荷预测模型(Python线性回归、随机森林、支持向量机、BP神经网络、GRU、LSTM)

文章目录 效果一览文章概述源码设计参考资料效果一览 文章概述 电力系统负荷预测模型(Python线性回归、随机森林、支持向量机、BP神经网络、GRU、LSTM) 所谓预测,就是指通过对事物进行分析及研究,并运用合理的方法探索事物的发展变化规律,对其未来发展做出预先估计和判断。…

Linux系统调试课:CPU 利用率中softirq飙高情况分析

文章目录 <font color=#0990d9>一、细化 CPU 利用率监控<font color=#0990d9>二、softirq飙高观测<font color=#0990d9>三、ksoftirqd机制沉淀、分享、成长,让自己和他人都能有所收获!😄 CPU 利用率是一个很笼统的概念,在遇到 CPU 利用率飙高的问题时,…

Spring Boot的打包方式:JAR vs. WAR 打包方式

Spring Boot的打包方式&#xff1a;JAR vs. WAR 打包方式 Spring Boot是一个流行的Java开发框架&#xff0c;提供了快速、便捷的应用程序开发和部署方式。本文将介绍Spring Boot的两种常见打包方式&#xff1a;JAR和WAR。我们将深入探讨它们的特点、适用场景和部署方式&#xf…

BUGKU-WEB 留言板

题目描述 题目无需登录后台&#xff01;需要xss平台接收flag&#xff0c; http协议需要http协议的xss平台打开场景后界面如下&#xff1a; 解题思路 看到此类的题目&#xff0c;应该和存储型xss有关&#xff0c;也就是将恶意代码保存到服务器端即然在服务器端&#xff0c;那就…

Linux操作系统基础(一):操作系统概述

文章目录 操作系统概述 一、计算机分类 二、计算机组成 三、操作系统概述 四、操作系统分类 操作系统概述 一、计算机分类 计算机一般分为个人计算机&#xff08;笔记、台式机&#xff09;与 企业级服务器&#xff08;1U、2U、机柜、塔式、刀片&#xff09;两种形式。 二…

初识C语言·预处理详解

目录 1 预定义符号 2 define定义常量 3 #define定义宏 4 带有副作用的宏 5 宏替换的规则 6 宏和函数的对比 7 # 和 ## i) #运算符 ii) ##运算符 8 命名约定 9 命令行定义 10 条件编译 条件编译1&#xff1a; 条件编译2&#xff1a; 条件编译3&#xff1a; 条件…

Vue源码系列讲解——变化侦测篇【下】(Array的变化侦测)

目录 1. 前言 2. 在哪里收集依赖 3. 使Array型数据可观测 3.1 思路分析 3.2 数组方法拦截器 3.3 使用拦截器 4. 再谈依赖收集 4.1 把依赖收集到哪里 4.2 如何收集依赖 4.3 如何通知依赖 5. 深度侦测 6. 数组新增元素的侦测 7. 不足之处 8. 总结 1. 前言 上一篇文…

gh0st远程控制——客户端界面编写(三)

◉ 主控端界面添加右键弹出菜单的功能 为Onlie_List区域添加右键弹出菜单项的功能&#xff1a; 3个视图&#xff1a;类视图、解决方案视图、资源视图 在资源视图下添加一个Menu&#xff1a; 更改Menu的ID为IDR_MENU_ONLINE&#xff1a; 为各控件添加便于区分的ID&#xff1a…