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,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.mfbz.cn/a/386315.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【算法分析与设计】环形链表

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;算法分析与设计 ⛺️稳中求进&#xff0c;晒太阳 题目 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次…

缓慢变化维 常用的处理方法

什么是缓慢变化维 维度 在数仓中&#xff0c;表往往会被划分成两种类型&#xff0c;一种是 事实表&#xff0c;另一种是维度表&#xff0c;举个例子&#xff0c;比如说&#xff1a; ❝ 2024年2月14日&#xff0c;健鑫在12306上买了两张火车票&#xff0c;每张火车票400元&…

TinUI v5预发布记录

TinUI v5预发布记录 前言新控件滚动选择框菜单按钮 新样式pre1pre2pre3 新功能导入字体文件 前言 TinUI是一个从2021年正式开始并一直维护到现在的小项目&#xff0c;中间经过了四代版本的更新。因为一些原因&#xff0c;2023年&#xff0c;TinUI-4后更新较少。 TinUI发展历程…

jmeter-问题二:JMeter进行文件上传时,常用的几种MIME类型

以下是一些常用的MIME类型及其对应的文件扩展名&#xff1a; 文本类型: text/plain: 通常用于纯文本文件&#xff0c;如 .txt 文件。 text/html: 用于HTML文档&#xff0c;即 .html 文件。 application/msword: Microsoft Word文档&#xff0c;即 .doc 和 .docx 文件。 图像…

英伟达市值超越谷歌!老黄隔空回应Altman的巨资筹款计划:没必要,真的没必要!

凭借算力上的霸主地位&#xff0c;英伟达正稳步成为科技领域的下一个巨头&#xff0c;在不久的15个月前&#xff0c;英伟达的市值还不足3000亿美元。然而&#xff0c;截至昨日&#xff0c;英伟达股价飙升使其市值达到了1.83万亿美元&#xff0c;超越了Alphabet&#xff08;谷歌…

传输层DoS

传输层是国际标准化组织提出的开放系统互联参考模型&#xff08;OSI&#xff09;中的第四 层。该层协议为网络端点主机上的进程之间提供了可靠、有效的报文传送服务。 平时我们所谈论的拒绝服务攻击大多是基于TCP的&#xff0c;因为现实中拒绝服务的对象 往往都是提供HTTP服务的…

Java类加载

Java类加载机制是Java虚拟机&#xff08;JVM&#xff09;的一个核心组成部分&#xff0c;它负责将Java类从不同的数据源&#xff08;如本地文件系统、网络等&#xff09;加载到JVM中&#xff0c;并为之生成对应的java.lang.Class对象。理解Java类加载机制对于深入理解Java运行时…

Python中多种生成随机密码超实用实例

前言 密码是信息安全的基石&#xff0c;它用于保护我们的账户、数据和隐私。为了确保密码足够强大&#xff0c;需要生成随机密码。在本文中&#xff0c;将讨论多种Python方法&#xff0c;用于生成随机密码的实用示例和技巧。 目录 ​编辑 前言 密码生成的要求 使用secrets…

创新S3存储桶检索:Langchain社区S3加载器搭载OpenAI API

在瞬息万变的数据存储和处理领域&#xff0c;将高效的云存储解决方案与先进的 AI 功能相结合&#xff0c;为处理大量数据提供了一种变革性的方法。本文演示了使用 MinIO、Langchain 和 OpenAI 的 GPT-3.5 模型的实际实现&#xff0c;重点总结了存储在 MinIO 存储桶中的文档。 …

C++ 音视频原理

本篇文章我们来描述一下音视频原理 音视频录制原理: 下面是对这张思维导图的介绍 摄像头部分: 麦克风采集声音 摄像头采集画面 摄像头采集回来的数据可以用RGB也可以用YUV来表示 图像帧帧率 一秒能处理多少张图像 图像处理 &#xff1a;调亮度 图像帧队列 :意思是将数据取…

【51单片机】LCD1602(江科大)

1.LCD1602介绍 LCD1602(Liquid Crystal Display)液晶显示屏是一种字符型液晶显示模块,可以显示ASCII码的标准字符和其它的一些内置特殊字符,还可以有8个自定义字符 显示容量:162个字符,每个字符为5*7点阵 2.引脚及应用电路 3.内部结构框图 屏幕: 字模库:类似于数码管的数…

【JVM篇】什么是jvm

文章目录 &#x1f354;什么是Java虚拟机&#x1f6f8;Java虚拟机有什么用&#x1f339;Java虚拟机的功能&#x1f388;Java虚拟机的组成 &#x1f354;什么是Java虚拟机 JVM指的是Java虚拟机&#xff0c;本质上是一个运行在计算机上的程序&#xff0c;可以运行 Java字节码文件…

微信小程序开发学习笔记《17》uni-app框架-tabBar

微信小程序开发学习笔记《17》uni-app框架-tabBar 博主正在学习微信小程序开发&#xff0c;希望记录自己学习过程同时与广大网友共同学习讨论。建议仔细阅读uni-app对应官方文档 一、创建tabBar分支 运行如下的命令&#xff0c;基于master分支在本地创建tabBar子分支&#x…

Spring Boot3自定义异常及全局异常捕获

⛰️个人主页: 蒾酒 &#x1f525;系列专栏&#xff1a;《spring boot实战》 &#x1f30a;山高路远&#xff0c;行路漫漫&#xff0c;终有归途。 目录 前置条件 目的 主要步骤 定义自定义异常类 创建全局异常处理器 手动抛出自定义异常 前置条件 已经初始化好一个…

17 ABCD数码管显示与动态扫描原理

1. 驱动八位数码管循环点亮 1.1 数码管结构图 数码管有两种结构&#xff0c;共阴极和共阳极&#xff0c;ACX720板上的是共阳极数码管&#xff0c;低电平点亮。 1.2 三位数码管等效电路图 为了节约I/O接口&#xff0c;各个数码管的各段发光管被连在一起&#xff0c;通过sel端…

【Spring框架】Spring事务同步

目录 一、什么是Spring事务同步 二、 事务同步管理器 2.1 TransactionSynchronizationManager事务同步管理器 2.1.1 资源同步 2.1.2 事务同步 2.1.3 总结 三、事务同步管理器保障事务的原理 四、spring事务为何使用TransactionSynchronizationManager spring源码实现 …

详解CC++内存管理(new和delete)

文章目录 写在前面1. C&C内存分布2. C语言中动态内存管理方式&#xff1a;malloc/calloc/realloc/free3. C内存管理方式&#xff08;语法&#xff09;3.1 new/delete操作内置类型3.2 new和delete操作自定义类型 4. new和delete的实现原理4.1 operator new与operator delete…

企业架构师的人格特质

L - Learning 持续学习的能力A - Abstracting 概念抽象的能力C1 - Connecting 联结事物的能力C2 - Compromising 平衡折衷的能力D - Decisioning 果断决策的能力 参考文章的链接

再利用系统盘时,如何删除恢复分区(Recovery Partition)

系统盘有一个Recovery Partition&#xff0c;记录了重要的系统信息&#xff0c;不能删除。 Windows 10的 Disk Managment 不提供用户删除这个Partition的选项。 近日我插入一块原系统盘&#xff0c;Format后作为DataDisk&#xff0c;此时需要删除这块硬盘上的RecoveryPartition…

Redis中内存淘汰算法实现

Redis中内存淘汰算法实现 Redis的maxmemory支持的内存淘汰机制使得其成为一种有效的缓存方案&#xff0c;成为memcached的有效替代方案。 当内存达到maxmemory后&#xff0c;Redis会按照maxmemory-policy启动淘汰策略。 Redis 3.0中已有淘汰机制&#xff1a; noevictionall…
最新文章