json库 字符串类型解析

语法子集及解析思路:

在这里插入图片描述
上面的子集表示json字符串是由两个双引号夹着零至多个字符构成。
字符分为无转义字符和转义字符,转义字符有九种,比较特殊的是\uXXXX表示的Unicode字符。

解析思路
先解析了左双引号,然后开始解析中间的字符,遇到右双引号“"”表示解析结束,遇到"\"表示解析转义字符,继续检测’\‘后面的字符是否为合法转义字符,遇到’\0’表示字符串结尾,没有遇到右双引号,报错,否则就是默认字符,检测是否为合法默认字符。
由于事先不知道字符串长度,需要一个地方来存储解析结果,而且在解析字符串,数组,对象的时候,总是采取先进后出的方式访问数组,所以选择实现一个动态堆栈结构来存储解析结果。
在解析过程中可能会报错,这时候已经把之前合法的字符压入栈里,需要提前备份栈顶位置,在遇到错误的时候回退。

实现细节及遇到的问题;

  1. 动态堆栈有点特殊,是以字节存储的,每次可以压入任意大小的数据:
typedef struct {
    const char* json;
    char* stack;
    size_t size, top;
}lept_context;
  1. 解析完成将字符串压栈:
static void* lept_context_push(lept_context* c, size_t size) {
    void* ret;
    assert(size > 0);
    if (c->top + size >= c->size) {
        if (c->size == 0)
            c->size = LEPT_PARSE_STACK_INIT_SIZE;
        while (c->top + size >= c->size)
            c->size += c->size >> 1;  /* c->size * 1.5 */
        c->stack = (char*)realloc(c->stack, c->size);
    }
    ret = c->stack + c->top;
    c->top += size;
    return ret;
}

在压栈之前检查新加入的数据会不会超过栈容量,会的话对栈扩容,扩容前检查栈容量是否为0,为0要先初始化容量。

遇到的问题

在 C 语言中,字符串一般表示为空结尾字符串(null-terminatedstring),即以空字符(’\0’)代表字符串的结束。然而,JSON 字符串是允许含有空字符的,例如这个 JSON
“Hello\u0000World” 就是单个字符串,解析后为11个字符。如果纯粹使用空结尾字符来表示 JSON 解析后的结果,就没法处理空字符。

刚开始没看懂这段话,仔细想想如果把包含\0的json文本解析存到c数组里,那么\0后面的元素就看不到了,程序以为数组在\0处结束了。
见代码:

 char str[] = "aa\0b";
    printf("%s", str);  //aa
  1. c->top = head; 作用:还原栈顶,因为出错前可能把字符压入栈中,这些字符都是不需要的,直接将栈顶位置回退,后续继续解析就覆盖那些不需要的字符。

  2. 为什么需要字符串解析缓冲区?
    听缓冲区可能不太理解,其实就是需要一个中间区域保存解析了一半的结果,为什么不直接将解析的部分写入结果呢?我想的是这样会造成内存多次写入,浪费时间。

总结

  1. 学习了动态堆栈的扩容原理,了解了关于vector扩容选取1.5倍系数的原因。
    缓存友好,可以重用之前的空间。
    举例:k是增长倍数,c是容量
    在这里插入图片描述
    详细讲解:[1], [2]

  2. 学会Windows下用CRT检测内存泄漏的方法。
    官方文档

  3. 关于do{} while(0)语句的使用
    是为了确保宏定义不会受到大括号,分号的影响,始终像无返回值的函数(do语句保证宏执行,while(0)保证只执行一次)
    详细讲解:[1]

源代码

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值