cjson源代码解读(三) 解析字符串、数字、数组、对象

1.  解析数字

static const char *parse_number(cJSON *item,const char *num)
{
	double n=0,sign=1,scale=0;int subscale=0,signsubscale=1;

	if (*num==‘-‘) sign=-1,num++;	/* Has sign? */
	if (*num==‘0‘) num++;			/* is zero */
	if (*num>=‘1‘ && *num<=‘9‘)	do	n=(n*10.0)+(*num++ -‘0‘);	while (*num>=‘0‘ && *num<=‘9‘);	/* Number? */
	if (*num==‘.‘ && num[1]>=‘0‘ && num[1]<=‘9‘) {num++;		do	n=(n*10.0)+(*num++ -‘0‘),scale--; while (*num>=‘0‘ && *num<=‘9‘);}	/* Fractional part? */
	if (*num==‘e‘ || *num==‘E‘)		/* Exponent? */
	{	num++;if (*num==‘+‘) num++;	else if (*num==‘-‘) signsubscale=-1,num++;		/* With sign? */
		while (*num>=‘0‘ && *num<=‘9‘) subscale=(subscale*10)+(*num++ - ‘0‘);	/* Number? */
	}

	n=sign*n*pow(10.0,(scale+subscale*signsubscale));	/* number = +/- number.fraction * 10^+/- exponent */

	item->valuedouble=n;
	item->valueint=(int)n;
	item->type=cJSON_Number;
	return num;
}

item是传进来的cjson object, num是起始数字。

  1. 解析正负, 用sign 标记, -1 是负

  2. 判断是不是0

  3. 判断小数点前面的数字, 也就是 - 3.2 e 5  , 前面的3.2, 这个分为两部分, 小数点前和后

  4. e或者E,即科学计数的后半部分, 这个时候需要处理一下科学计数的部分是不是正或者负的问题, 用signsubscale 记录。

  5. 然后直接解析, 这里作者用了个小技巧, 作者直接在解析前面基数的部分, 解析出的是整数, 用scale记录, 最后用科学技术弄回来就OK了, 很巧妙。

  6. 然后返回数字, 解析出来一个Object。

2. 解析字符串

static const char *parse_string(cJSON *item,const char *str)
{
	const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2;
	if (*str!=‘\"‘) {ep=str;return 0;}	/* not a string! */

	while (*ptr!=‘\"‘ && *ptr && ++len) if (*ptr++ == ‘\\‘) ptr++;	/* Skip escaped quotes. */ //跳到字符串最后一个去

	out=(char*)cJSON_malloc(len+1);	/* This is how long we need for the string, roughly. */    //预申请一个字符串空间大小的空间
	if (!out) return 0;                                                                        //申请不成功则退出  

	ptr=str+1;ptr2=out;                                                                        //重新开始, ptr2设置成out开始的部位
	while (*ptr!=‘\"‘ && *ptr)
	{
		if (*ptr!=‘\\‘) *ptr2++=*ptr++;                                                    //正常情况下,直接跑下去就行
		else
		{
			ptr++;
			switch (*ptr)
			{
				case ‘b‘: *ptr2++=‘\b‘;	break;                                     //特殊情况, 则断掉就行
				case ‘f‘: *ptr2++=‘\f‘;	break;
				case ‘n‘: *ptr2++=‘\n‘;	break;
				case ‘r‘: *ptr2++=‘\r‘;	break;
				case ‘t‘: *ptr2++=‘\t‘;	break;
				case ‘u‘:	 /* transcode utf16 to utf8. */                   //unicode 则要单独处理
					uc=parse_hex4(ptr+1);ptr+=4;	/* get the unicode char. */  //parse hex 在后面, 就是把后四位都弄出来,

					if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0)	break;	/* check for invalid.	*/

					if (uc>=0xD800 && uc<=0xDBFF)	/* UTF16 surrogate pairs.	*/
					{
						if (ptr[1]!=‘\\‘ || ptr[2]!=‘u‘)	break;	/* missing second-half of surrogate.	*/
						uc2=parse_hex4(ptr+3);ptr+=6;
						if (uc2<0xDC00 || uc2>0xDFFF)		break;	/* invalid second-half of surrogate.	*/
						uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF));
					}

					len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len;

					switch (len) {
						case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
						case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
						case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
						case 1: *--ptr2 =(uc | firstByteMark[len]);
					}
					ptr2+=len;
					break;
				default:  *ptr2++=*ptr; break;
			}
			ptr++;
		}
	}
	*ptr2=0;
	if (*ptr==‘\"‘) ptr++;
	item->valuestring=out;
	item->type=cJSON_String;
	return ptr;
}
static unsigned parse_hex4(const char *str)
{
	unsigned h=0;
	if (*str>=‘0‘ && *str<=‘9‘) h+=(*str)-‘0‘; else if (*str>=‘A‘ && *str<=‘F‘) h+=10+(*str)-‘A‘; else if (*str>=‘a‘ && *str<=‘f‘) h+=10+(*str)-‘a‘; else return 0;
	h=h<<4;str++;
	if (*str>=‘0‘ && *str<=‘9‘) h+=(*str)-‘0‘; else if (*str>=‘A‘ && *str<=‘F‘) h+=10+(*str)-‘A‘; else if (*str>=‘a‘ && *str<=‘f‘) h+=10+(*str)-‘a‘; else return 0;
	h=h<<4;str++;
	if (*str>=‘0‘ && *str<=‘9‘) h+=(*str)-‘0‘; else if (*str>=‘A‘ && *str<=‘F‘) h+=10+(*str)-‘A‘; else if (*str>=‘a‘ && *str<=‘f‘) h+=10+(*str)-‘a‘; else return 0;
	h=h<<4;str++;
	if (*str>=‘0‘ && *str<=‘9‘) h+=(*str)-‘0‘; else if (*str>=‘A‘ && *str<=‘F‘) h+=10+(*str)-‘A‘; else if (*str>=‘a‘ && *str<=‘f‘) h+=10+(*str)-‘a‘; else return 0;
	return h;
}

除了转码,剩下的都比较简单,就是申一个字符串, 然后拷过去。

3. 解析数组

static const char *parse_array(cJSON *item,const char *value)
{
	cJSON *child;
	if (*value!=‘[‘)	{ep=value;return 0;}	/* not an array! */

	item->type=cJSON_Array;
	value=skip(value+1);
	if (*value==‘]‘) return value+1;	/* empty array. */

	item->child=child=cJSON_New_Item();
	if (!item->child) return 0;		 /* memory fail */
	value=skip(parse_value(child,skip(value)));	/* skip any spacing, get the value. */
	if (!value) return 0;

	while (*value==‘,‘)
	{
		cJSON *new_item;
		if (!(new_item=cJSON_New_Item())) return 0; 	/* memory fail */
		child->next=new_item;new_item->prev=child;child=new_item;
		value=skip(parse_value(child,skip(value+1)));
		if (!value) return 0;	/* memory fail */
	}

	if (*value==‘]‘) return value+1;	/* end of array */
	ep=value;return 0;	/* malformed. */
}

  如果内容不是空, 然后一直往下解析。 就OK了。

4. 解析对象,对象以{}表明

static const char *parse_object(cJSON *item,const char *value)
{
	cJSON *child;
	if (*value!=‘{‘)	{ep=value;return 0;}	/* not an object! */

	item->type=cJSON_Object;
	value=skip(value+1);
	if (*value==‘}‘) return value+1;	/* empty array. */

	item->child=child=cJSON_New_Item();
	if (!item->child) return 0;
	value=skip(parse_string(child,skip(value)));
	if (!value) return 0;
	child->string=child->valuestring;child->valuestring=0;
	if (*value!=‘:‘) {ep=value;return 0;}	/* fail! */
	value=skip(parse_value(child,skip(value+1)));	/* skip any spacing, get the value. */
	if (!value) return 0;

	while (*value==‘,‘)
	{
		cJSON *new_item;
		if (!(new_item=cJSON_New_Item()))	return 0; /* memory fail */
		child->next=new_item;new_item->prev=child;child=new_item;
		value=skip(parse_string(child,skip(value+1)));
		if (!value) return 0;
		child->string=child->valuestring;child->valuestring=0;
		if (*value!=‘:‘) {ep=value;return 0;}	/* fail! */
		value=skip(parse_value(child,skip(value+1)));	/* skip any spacing, get the value. */
		if (!value) return 0;
	}

	if (*value==‘}‘) return value+1;	/* end of array */
	ep=value;return 0;	/* malformed. */
}

就是一个value,一个value往下滚, 然后自己的值用child记录, 前一个的位置也记录下来。 跟array没有什么大的区别。

主要就是这四个。

时间: 2024-10-10 20:57:14

cjson源代码解读(三) 解析字符串、数字、数组、对象的相关文章

cjson源代码解读 (二)解析流程

先从test.c 开始说, 我们看到test.c 里面有两个函数用来测试, doit 和dofile,  一个是读char* 一个是读file, 肯定是读字符串的要简单, 所以先看doit. /* Parse text to JSON, then render back to text, and print! */ void doit(char *text) { char *out;cJSON *json; json=cJSON_Parse(text); if (!json) {printf("

&lt;&lt;C++ Primer&gt;&gt; 第三章 字符串, 向量和数组 术语表

术语表 第 3 章 字符串, 向量和数组 begin: 是 string 和 vector 的成员,返回指向第一个元素的迭代器.也是一个标准库函数,输入一个数字,返回指向该数字首元素的指针. ?? 缓冲区溢出(buffer overflow): 一种严重的程序故障,主要的原因是试图通过一个越界的索引访问容器内容,容器类型包括 string,vector 和 数组等. ?? C 风格字符串(C-style string): 以空字符结束的字符数组.字符串字面值是 C 风格字符串,C风格字符串容易出

cjson源代码解读 (一)介绍

cjson是一个非常小巧的c语言写的json解析器, 代码比较短小精悍, c文件不过千行, 同类代码可在网页 json库 中找到.  项目地址如下: cjson地址 json的格式就不介绍了,  下面五个图能很好的解释json的格式. 一个object以{string:value...}的形式构成 也可以由数组构成 值可以是string, number, object, array, true, false等构成 string构造如下 number构造如下 json的介绍可以在 json格式介绍

第三章字符串.向量和数组

练习3.24:请使用迭代器重做3.3.3节的最后一个练习(读入一组整数并把他们存入一个vector对象,先输出第一个和最后一个元素的和,接着输出第二个和倒数第二个元素的和,以此类推) #include<iostream> #include<vector> using namespace std; int main() { int a; vector<int> v; while(cin>>a) v.push_back(a); auto head = v.beg

android解析二维数组对象key:value

JSONArray jsonArray = jsonObject.optJSONArray("data"); // array = dataObj.getJSONArray("data"); //JSONArray array = dataObj.getJSONArray("result"); if (jsonArray != null && jsonArray.length() > 0) { for (int i = 0;

javascript中字符串和数组的相互转换

javascript中字符串和数组的相互转换:字符串和数组的相互转换操作是非常的重要的,因为在实际编码过程中会经常用到,所以这是必须要掌握的知识点,当然这个知识点并不难,知道了就永远知道了,并不是那种需要充分实践才能够掌握的东西,下面就做一下简单的介绍.一.字符串转换为数组:此操作会用到split()函数,它能够以指定的字符作为分隔符,将字符串转换成一个数组,实例代码如下: var Str="abc-mng-zhang-mayi"; var newArray=Str.split(&qu

【c#】对象转json字符串/字符串转Json对象

using Newtonsoft.Json; 一.Hashtable转Json Hashtable hash = new Hashtable(); hash.Add("key1","val1"); hash.Add("key2","val2"); string json = JsonConvert.SerializeObject(hash);//{"key1":"val1","

jsoncpp封装和解析字符串、数字、布尔值和数组

使用jsoncpp进行字符串.数字.布尔值和数组的封装与解析. 1)下载jsoncpp的代码库 百度网盘地址 :http://pan.baidu.com/s/1ntqQhIT 2)解压缩文件 jsoncpp.rar unzip jsoncpp.rar 3)修改jsoncpp/src/main.cpp文件 vim src/main.cpp 1 #include <string> 2 #include <json/json.h> 3 #include "stdio.h&quo

Arduino学习笔记A6(补充) - 在串口读取多个字符串,并且转换为数字数组

功能如题目. 在串口收到逗号分割的6串数字比如 100,200,45,4,87,99 然后在6个PWM端口3, 5, 6, 9, 10, 11输出对应PWM值 代码注释很详细了,就不再说明了. ARDUINO 代码复制打印 //定义一个comdata字符串变量,赋初值为空值 String comdata = ""; //numdata是分拆之后的数字数组 int numdata[6] = {0}, PWMPin[6] = {3, 5, 6, 9, 10, 11}, mark = 0;