C++ JSON解析

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解析器

cpp 复制代码
#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
cpp 复制代码
#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
cpp 复制代码
#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
cpp 复制代码
#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
cpp 复制代码
#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

相关推荐
捕鲸叉3 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer3 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
Peter_chq3 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
青花瓷5 小时前
C++__XCode工程中Debug版本库向Release版本库的切换
c++·xcode
幺零九零零6 小时前
【C++】socket套接字编程
linux·服务器·网络·c++
捕鲸叉6 小时前
MVC(Model-View-Controller)模式概述
开发语言·c++·设计模式
Dola_Pan7 小时前
C++算法和竞赛:哈希算法、动态规划DP算法、贪心算法、博弈算法
c++·算法·哈希算法
yanlou2337 小时前
KMP算法,next数组详解(c++)
开发语言·c++·kmp算法
小林熬夜学编程7 小时前
【Linux系统编程】第四十一弹---线程深度解析:从地址空间到多线程实践
linux·c语言·开发语言·c++·算法
阿洵Rain8 小时前
【C++】哈希
数据结构·c++·算法·list·哈希算法