首页 > 编程语言 >C++写一个简单的JSON解析

C++写一个简单的JSON解析

时间:2024-11-01 20:25:11浏览次数:1  
标签:std name Val get ss value JSON C++ 解析

参考用C++编写一个简易的JSON解析器(1) 写一个动态类型 - 知乎

欢迎测试和反馈bug

首先,json包含string,number,integer,object,array,bool,null这些类型

对于object映射,使用map,对于array使用vector


我们定义一个类Val用来存储,使用variant来存储具体的值std::variant - cppreference.com

然后写好对应的初始化

class Val
{
public:
	using List = std::vector<Val>;
	using Dict = std::map<std::string, Val>;
	using val = std::variant<
		std::nullptr_t,
		int,
		bool,
		double,
		std::string,
		List,
		Dict>;
	Val() : value_(nullptr) {}
	Val(std::nullptr_t) : value_(nullptr) {}
	Val(int value) : value_(value) {}
	Val(double value) : value_(value) {}
	Val(const std::string& value) : value_(value) {}
	Val(const char* value) : value_(std::string(value)) {}
	Val(const List& value) : value_(value) {}
	Val(const Dict& value) : value_(value) {}
	Val(bool value) : value_(value) {}//避免隐式转换变成bool
	Val(std::initializer_list<Val> l) : value_(List(l)) {}
private:
	val value_;
};

接着为了方便输出数值,可以重载运算符

//记得在Val里	friend std::ostream& operator<<(std::ostream& out, const Val& v);
std::ostream& operator<<(std::ostream& out, const Val& v)
{
	if (std::holds_alternative<std::nullptr_t>(v.value_))
		out << "null";
	else if (std::holds_alternative<bool>(v.value_))
		out << (std::get<bool>(v.value_) ? "true" : "false");
	else if (std::holds_alternative<int>(v.value_))
		out << std::get<int>(v.value_);
	else if (std::holds_alternative<double>(v.value_))
		out << std::get<double>(v.value_);
	else if (std::holds_alternative<std::string>(v.value_))
		out << "\"" << std::get<std::string>(v.value_) << "\"";
	else if (std::holds_alternative<Val::List>(v.value_))
	{
		out << "[";
		const auto& list = std::get<Val::List>(v.value_);
		for (size_t i = 0; i < list.size(); ++i) {
			if (i > 0) out << ", ";
			out << list[i];
		}
		out << "]";
	}
	else if (std::holds_alternative<Val::Dict>(v.value_))
	{
		out << "{";
		const auto& dict = std::get<Val::Dict>(v.value_);
		for (auto it = dict.begin(); it != dict.end(); ++it)
		{
			if (it != dict.begin()) out << ", ";
			out << "\"" << it->first << "\": " << it->second;
		}
		out << "}";
	}
	return out;
}

测试下

int main()
{
	Val v1 = nullptr;
	Val v2 = true;
	Val v3 = 3.14;
	Val v4 = "Hello";
	Val::List list = { v1, v2, v3, v4 };
	Val v5 = list;
	Val::Dict dict = { {"key1", v1}, {"key2", v2}, {"key3", v3}, {"key4", v4}, {"key5", v5} };
	Val v6 = dict;
	std::cout << v1 << std::endl;
	std::cout << v2 << std::endl;
	std::cout << v3 << std::endl;
	std::cout << v4 << std::endl;
	std::cout << v5 << std::endl;
	std::cout << v6 << std::endl;
	return 0;
}

输出

nullptr
true
3.14
"Hello"
[nullptr, true, 3.14, "Hello"]
{"key1": nullptr, "key2": true, "key3": 3.14, "key4": "Hello", "key5": [nullptr, true, 3.14, "Hello"]}

为了方便使用,我们再重载[]

Val& operator[](const Val& val)
{
	if (std::holds_alternative<Val::Dict>(value_))
	{
		return std::get<Dict>(value_)[std::get<std::string>(val.value_)];
	}
	else if (std::holds_alternative<Val::List>(value_))
	{
		return std::get<List>(value_)[std::get<int>(val.value_)];
	}
	else if (std::holds_alternative<std::nullptr_t>(value_))
	{
		if (std::holds_alternative<std::string>(val.value_))
		{
			value_ = Dict({ {val, nullptr} });
			return std::get<Dict>(value_)[std::get<std::string>(val.value_)];
		}
		else if (std::holds_alternative<int>(val.value_))
		{
			int index = std::get<int>(val.value_);
			value_ = List(index + 1, nullptr);
			return std::get<List>(value_)[index];
		}

	}
	throw std::runtime_error("Not a dict or a list");
}
Val& operator[](const char* key)
{
	if (std::holds_alternative<Val::Dict>(value_))
	{
		return std::get<Dict>(value_)[key];
	}
	else if (std::holds_alternative<std::nullptr_t>(value_))
	{
		value_ = Dict({ {key, nullptr} });
		return std::get<Dict>(value_)[key];
	}
	throw std::runtime_error("Not a dictionary");
}

这样可以使用[]来输出内容

int main()
{
	Val v1 = {1,2,3,"haha",3.14};
	std::cout<<v1[2]<<' '<<v1[3]<<"\n";
	v1[2] = "hello world";
	std::cout<<v1<<"\n";
	Val::Dict v2;
	v2["nihao"] = 1;
	std::cout<<v2;
	return 0;
}

输出

3 "haha"
[1, 2, "hello world", "haha", 3.14]
{"nihao": 1}

 接下来我们添加两个函数,add用于list新数值的添加,put用于添加新的映射,

 

	void add(Val v)
	{
		if (std::holds_alternative<Val::List>(value_))
			std::get<List>(value_).push_back(v);
		else
		{
			if (std::holds_alternative<std::nullptr_t>(value_))
				value_ = List({ v });
			else
			{
				List l = { *this, v };
				value_ = l;
			}
		}
	}
	void put(const std::string& key, Val value)
	{
		if (std::holds_alternative<Val::Dict>(value_))
		{
			std::get<Dict>(value_)[key] = value;
		}
		else if (std::holds_alternative<std::nullptr_t>(value_))
		{
			value_ = Dict({ {key, value} });
		}
		else
			throw std::runtime_error("Not a dictionary");
	}

进行测试

int main()
{
	Val x;
	x.add("are u ok?");
	x.add("hello");
	x.add("3Q");
	Val y;
	y.put("phone",998244353);
	std::cout<<x<<"\n"<<y;
	return 0;
}

结果

["are u ok?", "hello", "3Q"]
{"phone": 998244353}

然后我们方便来直接获取Val的值写一些类型转换

operator std::nullptr_t() const { return std::get<std::nullptr_t>(value_); }
operator bool() const { return std::get<bool>(value_); }
operator int() const { return std::get<int>(value_); }
operator double() const { return std::get<double>(value_); }
operator std::string() const { return std::get<std::string>(value_); }
operator List() const { return std::get<List>(value_); }
operator Dict() const { return std::get<Dict>(value_); }

 测试

int main()
{
	Val x = "asdfg";
	std::string s = x;
	std::cout<<s;
	return 0;
}

输出

asdfg

那么我们的Val类到这里就告一段落了。接下来写parser类


首先,我们使用C++里的stringstream来帮我们完成字符串的顺序使用

class parser
{
public:
    
private:
	std::stringstream ss;
};

我们整个的流程是parse函数

	Val parse(const std::string& json)
	{
		ss.clear();
		ss << json;
		return parseVal();
	};

然后写一个parseVal用来详细解析并返回Val类型

    Val parseVal()
	{
		while (ss.peek() != -1)
		{
			skipSpace();
			char c = ss.peek();
			if (c == '"')
			{
				return parseStr();
			}
			else if (c == '[')
			{
				return parseList();
			}
			else if (c == '{')
			{
				return parseDict();
			}
			else if (c == 't' || c == 'f')
			{
				return parseBool();
			}
			else if (c == 'n')
			{
				return parseNull();
			}
			else
			{
				return parseNumber();
			}
		}
		return 0;
	}
  • 对于一个字符串,其中的空格,换行什么的都需要忽略掉
void skipSpace()
{
	char c = ss.peek();
	while (c == ' ' || c == '\n' || c == '\t' || c == '\r')
	{
		ss.get();
		c = ss.peek();
	}
}	
  • 如果碰到"那么接下来肯定是个字符串
    Val parseStr()
	{
		ss.get();//吃掉引号
		char c = ss.peek();
		std::string s;
		while (ss.peek() != '"')s.push_back(ss.get());
		ss.get();//吃掉引号
		return Val(s);
	}
  • 如果碰到左方括号,接下来是list
    Val parseList()
	{
		ss.get();//吃掉左括号
		skipSpace();
		Val::List l;
		while (ss.peek() != ']')
		{
			Val v = parseVal();
			l.push_back(v);
			char c = ss.peek();
			while (c == ',' || c == ' ' || c == '\n' || c == '\t' || c == '\r')
			{
				ss.get();
				c = ss.peek();
			}
		}
		ss.get();//吃掉右括号
		return l;
	}
  • 如果碰到左大括号,接下来肯定是dict
	Val parseDict()
	{
		ss.get();//吃掉左括号
		Val::Dict d;
		while (ss.peek() != '}')
		{
			skipSpace();
			Val key = parseStr();
			while (ss.peek() == ':' || ss.peek() == ' ')ss.get();//吃掉冒号
			Val value = parseVal();
			d[key] = value;
			while (ss.peek() == ' ' || ss.peek() == '\t' || ss.peek() == '\n' || ss.peek() == ',')ss.get();
		}
		ss.get();//吃掉右括号
		return d;
	}
  • 如果是t或f,那么肯定是bool类型
	Val parseBool()
	{
		if (ss.peek() == 'f')
		{
			ss.get(); ss.get(); ss.get(); ss.get(); ss.get();//吃掉 false
			return Val(false);
		}
		else
		{
			ss.get(); ss.get(); ss.get(); ss.get();//吃掉 true
			return Val(true);
		}
	}
  • 如果是n开头,那么是null
	Val parseNull()
	{
		ss.get(); ss.get(); ss.get(); ss.get();//吃掉 null
		return Val(nullptr);
	}
  • 剩下的就是数字了,或者是整型,或者是浮点型
	Val parseNumber()
	{
		std::string s;
		while (isdigit(ss.peek()) || ss.peek() == 'e' || ss.peek() == '-' || ss.peek() == '+' || ss.peek() == '.')s.push_back(ss.get());
		if (count(s.begin(), s.end(), '.') || count(s.begin(), s.end(), 'e'))
		{
			return stod(s);
		}
		else
		{
			return stoi(s);
		}
	}

 尝试解析一个VS Code的json文件

int main()
{
	parser p;
	std::string json = R"({
		"version": "0.2.0",
		"configurations": [
			{
				"name": "(Windows) 启动",
				"type": "cppvsdbg",
				"request": "launch",
				"program": "输入程序名称,例如 ${workspaceFolder}/a.exe",
				"args": [],
				"stopAtEntry": false,
				"cwd": "${fileDirname}",
				"environment": [],
				"console": "externalTerminal"
			}
		]
	})";
	std::cout << p.parse(json);
	return 0;
}

输出结果

{"configurations": [{"args": [], "console": "externalTerminal", "cwd": "${fileDirname}", "environment": [], "name": "(Windows) 启动", "program": "输入程序名称,例如 ${workspaceFolder}/a.exe", "request": "launch", "stopAtEntry": false, "type": "cppvsdbg"}], "version": "0.2.0"}

在一个txt里配置一个更复杂的json,然后进行一些测试

 效果

{"departments": [{"courses": [{"courseId": "CS101", "credits": 4, "students": [{"grade": "A", "id": 1, "name": "John Doe"}, {"grade": "B", "id": 2, "name": "Jane Smith"}], "title": "Introduction to Computer Science"}, {"courseId": "CS102", "credits": 3, "students": [{"grade": "A", "id": 3, "name": "Jim Brown"}, {"grade": "C", "id": 4, "name": "Jake White"}], "title": "Data Structures"}], "head": "Dr. Alice", "name": "Computer Science"}, {"courses": [{"courseId": "MATH101", "credits": 4, "students": [{"grade": "A", "id": 5, "name": "Alice Green"}, {"grade": "B", "id": 6, "name": "Bob Blue"}], "title": "Calculus I"}, {"courseId": "MATH102", "credits": 3, "students": [{"grade": "B", "id": 7, "name": "Charlie Black"}, {"grade": "A", "id": 8, "name": "Diana Yellow"}], "title": "Linear Algebra"}], "head": "Dr. Bob", "name": "Mathematics"}], "established": 1990, "events": [{"date": "2023-05-15", "name": "Science Fair", "participants": ["John Doe", "Jane Smith", "Jim Brown"]}, {"date": "2023-06-20", "name": "Math Olympiad", "participants": ["Alice Green", "Bob Blue", "Charlie Black"]}], "facilities": {"library": {"books": 50000, "name": "Central Library", "openHours": "8am - 8pm"}, "sportsComplex": {"name": "Sports Arena", "sports": ["Basketball", "Soccer", "Tennis"]}}, "isPublic": true, "location": {"city": "Example City", "country": "Example Country", "state": "Example State"}, "name": "Example School", "numbers": {"float": 3.14, "integer": 42, "negative_float": -3.14, "negative_integer": -42, "negative_scientific": -0.000123, "scientific": 12300}}
----------------
departments : [{"courses": [{"courseId": "CS101", "credits": 4, "students": [{"grade": "A", "id": 1, "name": "John Doe"}, {"grade": "B", "id": 2, "name": "Jane Smith"}], "title": "Introduction to Computer Science"}, {"courseId": "CS102", "credits": 3, "students": [{"grade": "A", "id": 3, "name": "Jim Brown"}, {"grade": "C", "id": 4, "name": "Jake White"}], "title": "Data Structures"}], "head": "Dr. Alice", "name": "Computer Science"}, {"courses": [{"courseId": "MATH101", "credits": 4, "students": [{"grade": "A", "id": 5, "name": "Alice Green"}, {"grade": "B", "id": 6, "name": "Bob Blue"}], "title": "Calculus I"}, {"courseId": "MATH102", "credits": 3, "students": [{"grade": "B", "id": 7, "name": "Charlie Black"}, {"grade": "A", "id": 8, "name": "Diana Yellow"}], "title": "Linear Algebra"}], "head": "Dr. Bob", "name": "Mathematics"}]
established : 1990
events : [{"date": "2023-05-15", "name": "Science Fair", "participants": ["John Doe", "Jane Smith", "Jim Brown"]}, {"date": "2023-06-20", "name": "Math Olympiad", "participants": ["Alice Green", "Bob Blue", "Charlie Black"]}]
facilities : {"library": {"books": 50000, "name": "Central Library", "openHours": "8am - 8pm"}, "sportsComplex": {"name": "Sports Arena", "sports": ["Basketball", "Soccer", "Tennis"]}}
isPublic : true
location : {"city": "Example City", "country": "Example Country", "state": "Example State"}
name : "Example School"
numbers : {"float": 3.14, "integer": 42, "negative_float": -3.14, "negative_integer": -42, "negative_scientific": -0.000123, "scientific": 12300}
"Example City"
[{"courseId": "MATH101", "credits": 4, "students": [{"grade": "A", "id": 5, "name": "Alice Green"}, {"grade": "B", "id": 6, "name": "Bob Blue"}], "title": "Calculus I"}, {"courseId": "MATH102", "credits": 3, "students": [{"grade": "B", "id": 7, "name": "Charlie Black"}, {"grade": "A", "id": 8, "name": "Diana Yellow"}], "title": "Linear Algebra"}, "C++"]
"def"
完整代码
#include <variant>
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <initializer_list>
#include <sstream>
#include <fstream>
#include <algorithm>
class Val
{
public:
	using List = std::vector<Val>;
	using Dict = std::map<std::string, Val>;
	using val = std::variant<
		std::nullptr_t,
		int,
		bool,
		double,
		std::string,
		List,
		Dict>;
	Val() : value_(nullptr) {}
	Val(std::nullptr_t) : value_(nullptr) {}
	Val(int value) : value_(value) {}
	Val(double value) : value_(value) {}
	Val(const std::string& value) : value_(value) {}
	Val(const char* value) : value_(std::string(value)) {}
	Val(const List& value) : value_(value) {}
	Val(const Dict& value) : value_(value) {}
	Val(bool value) : value_(value) {}//避免隐式转换变成bool
	Val(std::initializer_list<Val> l) : value_(List(l)) {}

	void add(Val v)
	{
		if (std::holds_alternative<Val::List>(value_))
			std::get<List>(value_).push_back(v);
		else
		{
			if (std::holds_alternative<std::nullptr_t>(value_))
				value_ = List({ v });
			else
			{
				List l = { *this, v };
				value_ = l;
			}
		}
	}
	void put(const std::string& key, Val value)
	{
		if (std::holds_alternative<Val::Dict>(value_))
		{
			std::get<Dict>(value_)[key] = value;
		}
		else if (std::holds_alternative<std::nullptr_t>(value_)) // 如果没有元素,就把key和value作为第一个元素的dict
		{
			value_ = Dict({ {key, value} });
		}
		else
			throw std::runtime_error("Not a dictionary");
	}
	Val& operator[](const Val& val)
	{
		if (std::holds_alternative<Val::Dict>(value_))
		{
			return std::get<Dict>(value_)[std::get<std::string>(val.value_)];
		}
		else if (std::holds_alternative<Val::List>(value_))
		{
			return std::get<List>(value_)[std::get<int>(val.value_)];
		}
		else if (std::holds_alternative<std::nullptr_t>(value_))
		{
			if (std::holds_alternative<std::string>(val.value_))
			{
				value_ = Dict({ {val, nullptr} });
				return std::get<Dict>(value_)[std::get<std::string>(val.value_)];
			}
			else if (std::holds_alternative<int>(val.value_))
			{
				int index = std::get<int>(val.value_);
				value_ = List(index + 1, nullptr); // 生成一个新的List,并填充nullptr
				return std::get<List>(value_)[index];
			}

		}
		throw std::runtime_error("Not a dict or a list");
	}
	Val& operator[](const char* key)
	{
		if (std::holds_alternative<Val::Dict>(value_))
		{
			return std::get<Dict>(value_)[key];
		}
		else if (std::holds_alternative<std::nullptr_t>(value_)) // 如果没有元素,就把key和value作为第一个元素的dict
		{
			value_ = Dict({ {key, nullptr} });
			return std::get<Dict>(value_)[key];
		}
		throw std::runtime_error("Not a dictionary");
	}

	friend std::ostream& operator<<(std::ostream& out, const Val& v);

	// 类型转换运算符
	operator std::nullptr_t() const { return std::get<std::nullptr_t>(value_); }
	operator bool() const { return std::get<bool>(value_); }
	operator int() const { return std::get<int>(value_); }
	operator double() const { return std::get<double>(value_); }
	operator std::string() const { return std::get<std::string>(value_); }
	operator List() const { return std::get<List>(value_); }
	operator Dict() const { return std::get<Dict>(value_); }

private:
	val value_;
};

std::ostream& operator<<(std::ostream& out, const class Val& v)
{
	if (std::holds_alternative<std::nullptr_t>(v.value_))
		out << "nullptr";
	else if (std::holds_alternative<bool>(v.value_))
		out << (std::get<bool>(v.value_) ? "true" : "false");
	else if (std::holds_alternative<int>(v.value_))
		out << std::get<int>(v.value_);
	else if (std::holds_alternative<double>(v.value_))
		out << std::get<double>(v.value_);
	else if (std::holds_alternative<std::string>(v.value_))
		out << "\"" << std::get<std::string>(v.value_) << "\"";
	else if (std::holds_alternative<Val::List>(v.value_))
	{
		out << "[";
		const auto& list = std::get<Val::List>(v.value_);
		for (size_t i = 0; i < list.size(); ++i) {
			if (i > 0) out << ", ";
			out << list[i];
		}
		out << "]";
	}
	else if (std::holds_alternative<Val::Dict>(v.value_))
	{
		out << "{";
		const auto& dict = std::get<Val::Dict>(v.value_);
		for (auto it = dict.begin(); it != dict.end(); ++it)
		{
			if (it != dict.begin()) out << ", ";
			out << "\"" << it->first << "\": " << it->second;
		}
		out << "}";
	}
	return out;
}

class parser
{
public:
	void skipSpace()
	{
		char c = ss.peek();
		while (c == ' ' || c == '\n' || c == '\t' || c == '\r')
		{
			ss.get();
			c = ss.peek();
		}
	}
	Val parse(const std::string& json)
	{
		ss.clear();
		ss << json;
		return parseVal();
	};
	Val parseVal()
	{
		while (ss.peek() != -1)
		{
			skipSpace();
			char c = ss.peek();
			if (c == '"')
			{
				return parseStr();
			}
			else if (c == '[')
			{
				return parseList();
			}
			else if (c == '{')
			{
				return parseDict();
			}
			else if (c == 't' || c == 'f')
			{
				return parseBool();
			}
			else if (c == 'n')
			{
				return parseNull();
			}
			else
			{
				return parseNumber();
			}
		}
		return 0;
	}
	Val parseStr()
	{
		ss.get();//吃掉引号
		char c = ss.peek();
		std::string s;
		while (ss.peek() != '"')s.push_back(ss.get());
		ss.get();//吃掉引号
		return Val(s);
	}
	Val parseList()
	{
		ss.get();//吃掉左括号
		skipSpace();
		Val::List l;
		while (ss.peek() != ']')
		{
			Val v = parseVal();
			l.push_back(v);
			char c = ss.peek();
			while (c == ',' || c == ' ' || c == '\n' || c == '\t' || c == '\r')
			{
				ss.get();
				c = ss.peek();
			}
		}
		ss.get();//吃掉右括号
		return l;
	}
	Val parseDict()
	{
		ss.get();//吃掉左括号
		Val::Dict d;
		while (ss.peek() != '}')
		{
			skipSpace();
			Val key = parseStr();
			while (ss.peek() == ':' || ss.peek() == ' ')ss.get();//吃掉冒号
			Val value = parseVal();
			d[key] = value;
			while (ss.peek() == ' ' || ss.peek() == '\t' || ss.peek() == '\n' || ss.peek() == ',')ss.get();
		}
		ss.get();//吃掉右括号
		return d;
	}
	Val parseBool()
	{
		if (ss.peek() == 'f')
		{
			ss.get(); ss.get(); ss.get(); ss.get(); ss.get();//吃掉 false
			return Val(false);
		}
		else
		{
			ss.get(); ss.get(); ss.get(); ss.get();//吃掉 true
			return Val(true);
		}
	}
	Val parseNull()
	{
		ss.get(); ss.get(); ss.get(); ss.get();//吃掉 null
		return Val(nullptr);
	}
	Val parseNumber()
	{
		std::string s;
		while (isdigit(ss.peek()) || ss.peek() == 'e' || ss.peek() == '-' || ss.peek() == '+')s.push_back(ss.get());
		if (count(s.begin(), s.end(), '.') || count(s.begin(), s.end(), 'e'))
		{
			return stof(s);
		}
		else
		{
			return stoi(s);
		}
	}

private:
	std::stringstream ss;
};

int main()
{
	std::ifstream fin("test.txt");
	std::stringstream ss;
	ss << fin.rdbuf();
	parser p;
	Val x = p.parse(ss.str());
	std::cout << x << std::endl;
	std::cout << "----------------\n";
	for (auto i : Val::Dict(x))
	{
		std::cout << i.first << " : " << i.second << std::endl;
	}
	std::cout << x[std::string("location")][std::string("city")] << "\n";
	x[std::string("departments")][1][std::string("courses")].add(Val("C++"));
	std::cout << x[std::string("departments")][1][std::string("courses")] << "\n";
	x.put("abc", "def");
	std::cout << x["abc"];
	return 0;
}

test文件

test.txt
{
    "name": "Example School",
    "location": {
        "city": "Example City",
        "state": "Example State",
        "country": "Example Country"
    },
    "established": 1990,
    "isPublic": true,
    "departments": [
        {
            "name": "Computer Science",
            "head": "Dr. Alice",
            "courses": [
                {
                    "courseId": "CS101",
                    "title": "Introduction to Computer Science",
                    "credits": 4,
                    "students": [
                        {"id": 1, "name": "John Doe", "grade": "A"},
                        {"id": 2, "name": "Jane Smith", "grade": "B"}
                    ]
                },
                {
                    "courseId": "CS102",
                    "title": "Data Structures",
                    "credits": 3,
                    "students": [
                        {"id": 3, "name": "Jim Brown", "grade": "A"},
                        {"id": 4, "name": "Jake White", "grade": "C"}
                    ]
                }
            ]
        },
        {
            "name": "Mathematics",
            "head": "Dr. Bob",
            "courses": [
                {
                    "courseId": "MATH101",
                    "title": "Calculus I",
                    "credits": 4,
                    "students": [
                        {"id": 5, "name": "Alice Green", "grade": "A"},
                        {"id": 6, "name": "Bob Blue", "grade": "B"}
                    ]
                },
                {
                    "courseId": "MATH102",
                    "title": "Linear Algebra",
                    "credits": 3,
                    "students": [
                        {"id": 7, "name": "Charlie Black", "grade": "B"},
                        {"id": 8, "name": "Diana Yellow", "grade": "A"}
                    ]
                }
            ]
        }
    ],
    "facilities": {
        "library": {
            "name": "Central Library",
            "books": 50000,
            "openHours": "8am - 8pm"
        },
        "sportsComplex": {
            "name": "Sports Arena",
            "sports": ["Basketball", "Soccer", "Tennis"]
        }
    },
    "events": [
        {
            "name": "Science Fair",
            "date": "2023-05-15",
            "participants": ["John Doe", "Jane Smith", "Jim Brown"]
        },
        {
            "name": "Math Olympiad",
            "date": "2023-06-20",
            "participants": ["Alice Green", "Bob Blue", "Charlie Black"]
        }
    ],
    "numbers": {
		"integer": 42,
		"negative_integer": -42,
		"float": 3.14,
		"negative_float": -3.14,
		"scientific": 1.23e4,
		"negative_scientific": -1.23e-4
	}
}

 

标签:std,name,Val,get,ss,value,JSON,C++,解析
From: https://www.cnblogs.com/qbning/p/18521086

相关文章

  • C++对象模型:object
    一、objecttypedefstruct{floatx;floaty;floatz;}Point3d;可以有以下方法打印上述类型字段:定义函数voidprint_point3d(constPoint3d*pd){printf("(%g,%g,%g)",pd->x,pd->y,pd->z);}若要更有效率,可以定义一个宏函数#definePoint3d_print(pd)......
  • C++多线程:atomic
    在许多为了性能和效率的场景下,需要开发一些lock-free的算法和数据结构atomic_flag原子布尔类型,只支持test-and-set和clear操作构造函数atomic_flag()noexcept=default;atomic_flag(constatomic_flag&)=delete;只有默认构造函数,而不能从其他对象构造atomic_flag对象需......
  • C++对象模型:constructor
    构造函数constructorexplicit的引入,是为了能够制止“单一参数的constructor”被当作一个conversion运算符带有默认构造函数的对象成员若一个类中包含对象成员,且该对象有默认构造函数,此时:若该类没有构造函数则编译器会合成一个默认构造函数,且发生在真正调用时若该类有构造函......
  • 深入解析 Transformers 框架(三):Qwen2.5 大模型的 AutoTokenizer 技术细节
    前面2篇文章,我们通过查看Transformers包代码,学习了Transformer包模块API设计、模型初始化和加载流程:第1篇:transformers推理Qwen2.5等大模型技术细节详解(一)transformers包和对象加载第2篇:transformers推理Qwen2.5等大模型技术细节详解(二)AutoModel初始化......
  • 【C++】类与对象(中)
    1.类的默认成员函数  默认成员函数就是用户没有显式实现,编译器会自动生成的成员函数称为默认成员函数。一个类,我们不写的情况下编译器会默认生成以下6个默认成员函数,需要注意的是这6个中最重要的是前4个,最后两个取地址重载不重要,我们稍微了解⼀下即可。其次就是C++11以后......
  • 深入解析 FastAPI 查询参数:配置、类型转换与灵活组合
    深入解析FastAPI查询参数:配置、类型转换与灵活组合本文全面解析了FastAPI查询参数的使用方法,包括配置默认值、设为可选或必选参数、类型转换以及组合使用等实用技巧。通过查询参数,开发者可以在路径操作函数中接收动态输入,灵活地构建API接口。文章详细说明了如何利用......
  • C++多线程:thread
    进程与线程进程:系统资源分配的最小单元,通常被定义为一个正在运行的程序实例线程:系统任务调度的最小单元进程间通信:管道,信号量,信号,消息队列,共享内存,套接字线程间通信:锁机制,信号量机制,信号机制,屏障同步:保证任务片段的先后顺序互斥:为了保证资源在同一时刻只能被一个线程使用,即......
  • C++多线程:mutex
    互斥量C++11互斥锁定义在<mutex>头文件中,提供了独占资源的特性C++11头文件中定义的互斥量互斥量说明mutex基本互斥量recursive_mutex递归互斥量timed_mutex定时互斥量recursive_timed_mutex递归定时互斥量std::mutex最基本的互斥量,提供了独占所有权......
  • C++多线程:condition_variable
    条件变量类似于pthread库中的pthread_cond_*()提供的功能,C++11标准提供了两种表示条件变量的类,分别是condition_variable和condition_variable_any,定义在头文件<condition_variable>中std::condition_variable当std::condition_variable对象调用wait()时,会阻塞当前线程,直到该s......
  • C++多线程:promise
    头文件包含:Providers类std::promisestd::packaged_taskFutures类std::futurestd::shared_futureProviders函数std::async()其他类型std::future_errorstd::future_errcstd::future_statusstd::launchstd::promise用来保存某一类型T的值,该值可以被future对......