简易的 C++ JSON解析器

Github地址:X-Thinker/JSON-Parser: 简易的JSON解析器/A Tiny JSON Parser (github.com)icon-default.png?t=N7T8https://github.com/X-Thinker/JSON-Parser

README:

CppJSON.h

#ifndef CppJSON_h
#define CppJSON_h

#include <iostream>
#include <sstream>
#include <typeinfo>
#include <fstream>
#include <memory>

namespace JSON
{
	/*----------JSON类型----------*/
	//抽象基类CppJSON,不可实例化
	class CppJSON
	{
	public:
		//类内枚举,定义JSON数据类型
		enum CppJSON_Type { JSON_Initial, JSON_Error, JSON_NULL, JSON_Bool, JSON_Number, JSON_String, JSON_Array, JSON_Object };

		//构造函数与析构函数,构造函数使用初始化列表,析构函数是虚函数
		CppJSON(CppJSON_Type ini = JSON_Initial, CppJSON* left = nullptr, CppJSON* right = nullptr,
			const std::string& key_name = "name") :type(ini), prev(left), next(right), child(nullptr), key("name") {}
		virtual ~CppJSON() = 0;

		//修改JSON数据结构内部成员变量
		void set_prev(CppJSON* left) { prev = left; }
		void set_next(CppJSON* right) { next = right; }
		void set_key(const std::string& name) { key = name; }
		void set_child(CppJSON* first) { child = first; }

		//返回JSON数据结构内部成员变量
		CppJSON* return_prev() const { return prev; }
		CppJSON* return_next() const { return next; }
		const std::string return_key() const { return key; }
		CppJSON* return_child() const { return child; }
		CppJSON_Type return_type()const { return type; }

		//纯虚函数,后续array和object需要覆写
		virtual CppJSON& operator [] (int pos) const;
		virtual CppJSON& operator [] (const std::string key_name) const;
		virtual void push_back(CppJSON* item);
		virtual void insert(CppJSON* item, int pos);
		virtual void split(int pos);
		virtual void split(const std::string& key_name);

	private:
		CppJSON_Type type;
		//同一结构中的前一个元素与后一个元素
		CppJSON* prev, * next, * child;
		std::string key;

		//禁用拷贝构造函数与赋值运算符重载(设为private并不予实现)
		CppJSON(const CppJSON& rhs) {}
		CppJSON& operator = (const CppJSON& rhs) {}
	};
	//错误类型用以处理异常情况
	class CppJSON_Error :public CppJSON
	{
	public:
		enum Error_Type { No_Error, Invalid_Type, Out_Range, Invalid_Key, Invalid_Json_Text, Bad_Allocate, Open_File_Fail, Unknown_Error };
		CppJSON_Error() :CppJSON(JSON_Error), error_type(No_Error), exception() {}
		~CppJSON_Error() {}
		CppJSON& operator [] (int pos);
		CppJSON& operator [] (std::string key_name);
		void throw_exception(Error_Type type);
	private:
		Error_Type error_type;
		std::string exception;
	};
	//值为null的数据类型
	class CppJSON_NULL :public CppJSON
	{
	public:
		CppJSON_NULL() :CppJSON(JSON_NULL) {}
		~CppJSON_NULL() {}
	};
	//值为false或true的数据类型
	class CppJSON_Bool :public CppJSON
	{
	public:
		CppJSON_Bool() :CppJSON(JSON_Bool), valuebool(false) {}
		~CppJSON_Bool() {}
		void set_valuebool(bool vb) { valuebool = vb; }
		bool return_valuebool() const { return valuebool; }
	private:
		bool valuebool;
	};
	//值为数值的数据类型
	class CppJSON_Number :public CppJSON
	{
	public:
		CppJSON_Number() :CppJSON(JSON_Number), valueint(0), valuedouble(0.0), numbertype(false) {}
		~CppJSON_Number() {}

		//修改/查询数值型JSON的数值
		void set_valueint(int vi) { valueint = vi; }
		int return_valueint() const { return valueint; }
		void set_valuedouble(double vd) { valuedouble = vd; }
		double return_valuedouble() const { return valuedouble; }
		void set_numbertype(bool nt) { numbertype = nt; }
		bool return_numbertype() const { return numbertype; }

	private:
		int valueint;
		double valuedouble;
		bool numbertype;//数值类型默认为false即int型,若为true则为double型
	};
	//值为字符串的数据类型
	class CppJSON_String :public CppJSON
	{
	public:

		CppJSON_String() :CppJSON(JSON_String) {}
		~CppJSON_String() {}

		void set_valuestring(const std::string& vs) { valuestring = vs; }
		std::string return_valuestring() const { return valuestring; }

	private:
		std::string valuestring;
	};
	//值为数组的数据类型
	class CppJSON_Array :public CppJSON
	{
	public:
		CppJSON_Array() :CppJSON(JSON_Array) {}
		~CppJSON_Array() {}

		//重载 [] 运算符,使数组类型可以通过下标直接访问其内部元素
		CppJSON& operator [] (int pos) const override;

		void push_back(CppJSON* item) override;
		void insert(CppJSON* item, int pos) override;
		void split(int pos) override;
	};
	//值为对象的数据类型
	class CppJSON_Object :public CppJSON
	{
	public:
		CppJSON_Object() :CppJSON(JSON_Object) {}
		~CppJSON_Object() {}

		//重载 [] 运算符使对象类型可以通过key直接访问其内部元素
		CppJSON& operator [] (const std::string key_name) const override;

		void push_back(CppJSON* item) override;
		void split(const std::string& key_name) override;
	};
	/*----------JSON类型----------*/



	/*----------对外接口----------*/
	//解析函数
	enum parser_mode { file, text };
	std::shared_ptr<CppJSON> parser(std::string str, parser_mode mode);
	std::shared_ptr<CppJSON> parser(char* str, parser_mode mode);
	//压缩json文本(删除空格、空行、注释)
	std::string minify(std::stringstream& message);
	std::string minify(std::string& msg);
	//重载 << 运算符方便输出
	std::ostream& operator << (std::ostream& os, CppJSON* JSON_Print);
	/*----------对外接口----------*/
}

#endif

CppJSON.cpp

#include "CppJSON.h"

namespace JSON
{
	//全局异常
	CppJSON_Error* error = new CppJSON_Error;

	/*----------类成员函数模块----------*/
	CppJSON::~CppJSON() {}
	CppJSON& CppJSON::operator [] (int pos) const { error->throw_exception(CppJSON_Error::Invalid_Type); return *error; }
	CppJSON& CppJSON::operator [] (const std::string key_name) const { error->throw_exception(CppJSON_Error::Invalid_Type); return *error; }
	void CppJSON::push_back(CppJSON* item) { error->throw_exception(CppJSON_Error::Invalid_Type); }
	void CppJSON::insert(CppJSON* item, int pos) { error->throw_exception(CppJSON_Error::Invalid_Type); }
	void CppJSON::split(int pos) { error->throw_exception(CppJSON_Error::Invalid_Type); }
	void CppJSON::split(const std::string& key_name) { error->throw_exception(CppJSON_Error::Invalid_Type); }


	//数组通过下标访问内部元素
	CppJSON& CppJSON_Array::operator [] (int pos) const
	{
		CppJSON* location = this->return_child();
		while (location != nullptr && pos > 0)
			location = location->return_next(), --pos;
		//越界异常,返回错误类型
		if (pos != 0 || location == nullptr)
		{
			error->throw_exception(CppJSON_Error::Out_Range);
			return *error;
		}
		return *location;
	}
	//对象通过关键字访问内部元素
	CppJSON& CppJSON_Object::operator [] (const std::string key_name) const
	{
		CppJSON* location = this->return_child();
		while (location != nullptr && key_name != location->return_key())
			location = location->return_next();
		//找不到关键字,返回错误类型
		if (location == nullptr)
		{
			error->throw_exception(CppJSON_Error::Invalid_Key);
			return *error;
		}
		return *location;
	}

	//在数组尾部加入新元素
	void CppJSON_Array::push_back(CppJSON* item)
	{
		CppJSON* preloc = this->return_child(), * loc = this->return_child();
		//空数组
		if (loc == nullptr) { this->set_child(item); return; }
		//非空数组
		while (loc != nullptr)
			preloc = loc, loc = loc->return_next();
		preloc->set_next(item);
		item->set_prev(preloc);
		return;
	}
	//在对象尾部加入新元素
	void CppJSON_Object::push_back(CppJSON* item)
	{
		CppJSON* preloc = this->return_child(), * loc = this->return_child();
		//空对象
		if (loc == nullptr) { this->set_child(item); return; }
		//非空对象
		while (loc != nullptr)
			preloc = loc, loc = loc->return_next();
		preloc->set_next(item);
		item->set_prev(preloc);
		return;
	}

	//在数组指定位置插入新元素
	void CppJSON_Array::insert(CppJSON* item, int pos)
	{
		//在头部插入
		if (pos == 0)
		{
			item->set_next(this->return_child());
			if (this->return_child() != nullptr)
				this->return_child()->set_prev(item);
			this->set_child(item);
			return;
		}
		CppJSON* prev_loc = &(*this)[pos - 1];
		//如果上述过程抛出异常直接退出
		if (typeid(*error) == typeid(*prev_loc))
			return;
		//如果pos-1的位置为队尾则退化成push_back
		if (prev_loc->return_next() != nullptr)
		{
			CppJSON* next_loc = prev_loc->return_next();
			prev_loc->set_next(item), item->set_prev(prev_loc);
			item->set_next(next_loc), next_loc->set_prev(item);
		}
		else
			prev_loc->set_next(item), item->set_prev(prev_loc);
		return;
	}

	//删除指定数组元素
	void CppJSON_Array::split(int pos)
	{
		CppJSON* detath_item = &(*this)[pos];
		if (typeid(*error) == typeid(*detath_item))
			return;
		//删除首元素
		if (pos == 0)
		{
			this->set_child(detath_item->return_next());
			if (detath_item->return_next() != nullptr)
				detath_item->return_next()->set_prev(nullptr);
			detath_item->set_next(nullptr);
			delete detath_item;
			return;
		}
		//非首元素
		detath_item->return_prev()->set_next(detath_item->return_next());
		if (detath_item->return_next() != nullptr)
			detath_item->return_next()->set_prev(detath_item->return_prev());
		detath_item->set_next(nullptr), detath_item->set_prev(nullptr);
		delete detath_item;
		return;
	}
	//删除指定对象元素
	void CppJSON_Object::split(const std::string& key_name)
	{
		CppJSON* detath_item = &(*this)[key_name];
		if (typeid(*error) == typeid(*detath_item))
			return;
		//删除首元素
		if (this->return_child() == detath_item)
		{
			this->set_child(detath_item->return_next());
			if (detath_item->return_next() != nullptr)
				detath_item->return_next()->set_prev(nullptr);
			detath_item->set_next(nullptr);
			delete detath_item;
			return;
		}
		//非首元素
		detath_item->return_prev()->set_next(detath_item->return_next());
		if (detath_item->return_next() != nullptr)
			detath_item->return_next()->set_prev(detath_item->return_prev());
		detath_item->set_next(nullptr), detath_item->set_prev(nullptr);
		delete detath_item;
		return;
	}
	/*----------类成员函数模块----------*/



	/*----------异常模块----------*/
	//对不同错误类型抛出不同异常
	void CppJSON_Error::throw_exception(Error_Type type)
	{
		switch (type)
		{
		case Invalid_Type: exception = "This procedure triggers an error \"Invalid type\""; break;
		case Out_Range: exception = "This procedure triggers an error \"Subscript out of range\""; break;
		case Invalid_Key: exception = "This procedure triggers an error \"Invalid key\""; break;
		case Invalid_Json_Text: exception = "This procedure triggers an error \"Invalid json texts\""; break;
		case Bad_Allocate: exception = "This procedure triggers an error \"Bad allocated\""; break;
		case Open_File_Fail: exception = "This procedure triggers an error \"Fail to open the file\""; break;
		default: exception = "This procedure triggers an unknown error"; break;
		}
		error_type = type;
		std::cout << exception << std::endl;
		return;
	}
	//错误类型的[]运算符重载,处理后续数组和对象在进行连续的[]访问中抛出的异常
	CppJSON& CppJSON_Error::operator [] (int pos) { throw_exception(Invalid_Type); return *error; }
	CppJSON& CppJSON_Error::operator [] (std::string key_name) { throw_exception(Invalid_Type); return *error; }
	//内存分配失败抛出异常
	CppJSON* bad_allocated() { error->throw_exception(CppJSON_Error::Bad_Allocate); return error; }
	//无效的Json文本抛出异常
	CppJSON* invalid_json_text(std::stringstream& message) 
	{
		error->throw_exception(CppJSON_Error::Invalid_Json_Text); 
		std::string fail_pos;
		getline(message, fail_pos);
		fail_pos += "(...omit...)";
		//把解析失败的行内容输出,方便用户检查json文本错误
		std::cout << "Parsing failed: " << fail_pos << std::endl;
		return error;
	}
	/*----------异常模块----------*/



	/*---------功能函数模块---------*/
	//删除整个json结构
	void delete_json(CppJSON* detach_json)
	{
		CppJSON* next = detach_json;
		while (detach_json)
		{
			next = detach_json->return_next();
			if (detach_json->return_child() != nullptr)
				delete_json(detach_json->return_child());
			delete detach_json;
			detach_json = next;
		}
		return;
	}
	//压缩json文本,去除空白格与格式
	std::string minify(std::stringstream& message) 
	{
		std::string msg = message.str(); 
		return minify(msg);
	}
	std::string minify(std::string& msg)
	{
		int point_write = 0, point_read = 0;
		while (msg[point_read] != '\0')
		{
			switch (msg[point_read])
			{
			case ' ': ++point_read; break;
			case '\n': ++point_read; break;
			case '\r': ++point_read; break;
			case '\t': ++point_read; break;//跳过空白格
			case '\"':
				msg[point_write++] = msg[point_read++];
				while (msg[point_read] != '\0' && msg[point_read] != '\"')
					msg[point_write++] = msg[point_read++];
				msg[point_write++] = msg[point_read++];
				break;
			default: msg[point_write++] = msg[point_read++]; break;
			}
		}
		msg[point_write] = '\0';
		std::string res(msg, 0, ++point_write);
		std::cout << res << std::endl;
		return res;
	}
	//跳过空白格
	std::stringstream& skip_whitespace(std::stringstream& message) { while (message.peek() > 0 && message.peek() <= 32) message.ignore(); return message; }
	//获取一个元素的key值
	bool get_keyname(std::string& kn, std::stringstream& message)
	{
		if (message.peek() != '\"')
			return false;
		message.ignore();
		kn.clear();
		getline(message, kn, '\"');
		if (kn.size())
			return true;
		else
			return false;
	}
	/*---------功能函数模块---------*/



	/*----------解析模块----------*/
	//前置声明
	CppJSON* parse_object(std::stringstream& message);
	//以string参数进行解析
	std::shared_ptr<CppJSON> parser(std::string path, parser_mode mode)
	{
		std::stringstream json_text;
		if (mode == file)
		{
			std::ifstream fin(path);
			//文件打开失败抛出异常
			if (!fin.is_open())
			{
				error->throw_exception(CppJSON_Error::Open_File_Fail);
				return std::shared_ptr<CppJSON>(error);
			}
			//将fin流中内容输入到json_text
			json_text << fin.rdbuf();
			fin.close();
		}
		else if (mode == text)
			json_text << path;
		else//如果解析模式错误则会抛出未知错误
		{
			error->throw_exception(CppJSON_Error::Unknown_Error);
			return std::shared_ptr<CppJSON>(error);
		}
		CppJSON* res = parse_object(skip_whitespace(json_text));
		//在json文本后有除终止符外的其他非空白字符
		if (skip_whitespace(json_text).peek() != -1)
		{
			invalid_json_text(json_text);
			return std::shared_ptr<CppJSON>(error);
		}
		if (typeid(*res) == typeid(*error)) 
			return std::shared_ptr<CppJSON>(error);
		std::shared_ptr<CppJSON> ptr(res, delete_json);
		std::cout << ptr.get() << std::endl;
		return ptr;
	}
	//以char*参数进行解析,兼容C
	std::shared_ptr<CppJSON> parser(char* path, parser_mode mode)
	{
		//把char*的内容导入string后用parser的string重载完成解析
		std::string ps(path);
		return parser(ps, mode);
	}

	//解析函数
	//前置声明
	CppJSON* parse_null(std::stringstream& message);
	CppJSON* parse_bool(std::stringstream& message);
	CppJSON* parse_string(std::stringstream& message);
	CppJSON* parse_number(std::stringstream& message);
	CppJSON* parse_array(std::stringstream& message);
	CppJSON* parse_object(std::stringstream& message);

	CppJSON* parse_value(std::stringstream& message)
	{
		char ch_mes = message.peek();
		if (ch_mes == 'n')
			return parse_null(message);
		else if (ch_mes == 'f' || ch_mes == 't')
			return parse_bool(message);
		else if (ch_mes == '\"')
			return parse_string(message);
		else if (ch_mes == '-' || ch_mes == '+' || isdigit(ch_mes))
			return parse_number(message);
		else if (ch_mes == '[')
			return parse_array(message);
		else if (ch_mes == '{')
			return parse_object(message);
		else//如果出现错误情况,抛出无效Json文本异常
			return invalid_json_text(message);
	}
	CppJSON* parse_null(std::stringstream& message)
	{
		//检查是否为有效的null值
		if (message.peek() != 'n')
			return invalid_json_text(message);
		CppJSON_NULL* item_null = new CppJSON_NULL;
		//分配失败抛出异常
		if (item_null == nullptr)
			return bad_allocated();
		message.ignore(4);//null四个字符
		return item_null;
	}
	CppJSON* parse_bool(std::stringstream& message)
	{
		char ch = message.peek();
		if (ch != 'f' && ch != 't')
			return invalid_json_text(message);
		CppJSON_Bool* item_bool = new CppJSON_Bool;
		if (item_bool == nullptr)
			return bad_allocated();
		//设置bool的类型
		if (ch == 'f') item_bool->set_valuebool(false), message.ignore(5);
		else item_bool->set_valuebool(true), message.ignore(4);
		return item_bool;
	}
	CppJSON* parse_string(std::stringstream& message)
	{
		if (message.peek() != '\"')
			return invalid_json_text(message);
		CppJSON_String* item_string = new CppJSON_String;
		if (item_string == nullptr)
			return bad_allocated();
		std::string vs;
		message.ignore();
		//以"为分割符,将string值抽出
		getline(message, vs, '\"');
		item_string->set_valuestring(vs);
		return item_string;
	}
	CppJSON* parse_number(std::stringstream& message)
	{
		char ch_mes = message.peek();
		if (ch_mes != '-' && ch_mes != '+' && !isdigit(ch_mes))
			return invalid_json_text(message);
		std::string num_string;
		bool num_type = false;
		//值为number的所有可能出现的字符
		while (ch_mes == '-' || ch_mes == '+' || ch_mes == 'e' || ch_mes == 'E' || ch_mes == '.' || isdigit(ch_mes))
			num_string.push_back(message.get()), ch_mes = message.peek(), num_type = (ch_mes == '.' || ch_mes == 'e' || ch_mes == 'E') ? true : false;
		CppJSON_Number* item_number = new CppJSON_Number;
		if (item_number == nullptr)
			return bad_allocated();
		//根据数字中是否出现小数点或者科学计数法来判断数值为double或int
		item_number->set_numbertype(num_type);
		if (num_type)
			item_number->set_valuedouble(std::stod(num_string));
		else
			item_number->set_valueint(std::stoi(num_string));
		return item_number;
	}
	CppJSON* parse_array(std::stringstream& message)
	{
		if (message.peek() != '[')
			return invalid_json_text(message);
		message.ignore();
		CppJSON_Array* item_array = new CppJSON_Array;
		if (item_array == nullptr)
			return bad_allocated();
		CppJSON* item_child = parse_value(skip_whitespace(message));
		//解析失败抛出异常
		if (typeid(*item_child) == typeid(*error))
			return error;
		//连接子结点
		item_array->set_child(item_child);

		CppJSON* item_otherchild = nullptr;
		while (skip_whitespace(message).peek() == ',')
		{
			message.ignore();
			item_otherchild = parse_value(skip_whitespace(message));
			if (typeid(*item_otherchild) == typeid(*error))
				return error;
			//连接各子结点
			item_child->set_next(item_otherchild), item_otherchild->set_prev(item_child);
			item_child = item_otherchild;
		}

		if (message.peek() != ']')
			return invalid_json_text(message);
		message.ignore();
		return item_array;
	}
	CppJSON* parse_object(std::stringstream& message)
	{
		if (message.peek() != '{')
			return invalid_json_text(message);
		message.ignore();
		CppJSON* item_object = new CppJSON_Object;
		if (item_object == nullptr)
			return bad_allocated();
		//对象中为key-value键值对,所以首先应该出现key或者 }(空的对象)
		if (skip_whitespace(message).peek() == '}')
			return item_object;
		if (message.peek() != '\"')
			return invalid_json_text(message);

		//message.ignore();
		std::string item_keyname;
		//key值解析失败
		if (!get_keyname(item_keyname, message))
			return invalid_json_text(message);
		if (skip_whitespace(message).peek() != ':')
			return invalid_json_text(message);

		message.ignore();
		CppJSON* item_child = parse_value(skip_whitespace(message));
		if (typeid(*item_child) == typeid(*error))
			return error;
		item_child->set_key(item_keyname);
		item_object->set_child(item_child);

		CppJSON* item_otherchild = nullptr;
		while (skip_whitespace(message).peek() == ',')
		{
			message.ignore(), skip_whitespace(message);
			if (!get_keyname(item_keyname, message))
				return invalid_json_text(message);
			if (skip_whitespace(message).peek() != ':')
				return invalid_json_text(message);
			message.ignore();
			item_otherchild = parse_value(skip_whitespace(message));
			if (typeid(*item_otherchild) == typeid(*error))
				return error;
			item_otherchild->set_key(item_keyname);
			item_child->set_next(item_otherchild), item_otherchild->set_prev(item_child);
			item_child = item_otherchild;
		}

		if (message.peek() != '}')
			return invalid_json_text(message);
		message.ignore();
		return item_object;
	}
	/*----------解析模块----------*/



	/*----------输出模块----------*/
	//静态全局变量deep用来反映输出时的递归深度以格式化输出
	static int print_deep = 0;
	//输出函数
	std::ostream& print_bool(std::ostream& os, CppJSON_Bool* pb) { pb->return_valuebool() ? os << "true" : os << "false"; return os; }
	std::ostream& print_null(std::ostream& os, CppJSON_NULL* pn) { os << "null"; return os; }
	std::ostream& print_string(std::ostream& os, CppJSON_String* ps) { os << '\"' << ps->return_valuestring() << '\"'; return os; }
	std::ostream& print_number(std::ostream& os, CppJSON_Number* pn) { pn->return_numbertype() ? os << pn->return_valuedouble() : os << pn->return_valueint(); return os; }
	std::ostream& print_array(std::ostream& os, CppJSON_Array* pa)
	{
		os << '[';
		CppJSON* pa_child = pa->return_child();
		while (pa_child != nullptr)
		{
			os << pa_child;
			pa_child = pa_child->return_next();
			if (pa_child != nullptr)
				os << ", ";
		}
		os << ']';
		return os;
	}
	std::ostream& print_object(std::ostream& os, CppJSON_Object* po)
	{
		++print_deep, os << '{';
		CppJSON* po_child = po->return_child();
		if (po_child != nullptr) os << '\n';
		while (po_child != nullptr)
		{
			for (int i = 1; i <= print_deep; i++)
				os << '\t';
			os << '\"' << po_child->return_key() << "\":\t";
			os << po_child;
			po_child = po_child->return_next();
			if (po_child != nullptr)
				os << ',';
			os << '\n';
		}
		for (int i = 1; i <= print_deep - 1; i++) os << '\t';
		--print_deep, os << '}';
		return os;
	}
	std::ostream& operator << (std::ostream& os, CppJSON* JSON_Print)
	{
		switch (JSON_Print->return_type())
		{
		case CppJSON::JSON_Bool: return print_bool(os, dynamic_cast<CppJSON_Bool*>(JSON_Print)); break;
		case CppJSON::JSON_NULL:return print_null(os, dynamic_cast<CppJSON_NULL*>(JSON_Print)); break;
		case CppJSON::JSON_String: return print_string(os, dynamic_cast<CppJSON_String*>(JSON_Print)); break;
		case CppJSON::JSON_Number: return print_number(os, dynamic_cast<CppJSON_Number*>(JSON_Print)); break;
		case CppJSON::JSON_Array: return print_array(os, dynamic_cast<CppJSON_Array*>(JSON_Print)); break;
		case CppJSON::JSON_Object: return print_object(os, dynamic_cast<CppJSON_Object*>(JSON_Print)); break;
		default: error->throw_exception(CppJSON_Error::Invalid_Type); return os; break;
		}
	}
	/*----------输出模块----------*/
}

 

  • 8
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值