lept_json的学习之stringify

这一节我们讲解所有类型的生成Stringify。
其实stringify的意思本不是生成,而是字符串化,但为了方便理解,我直接称之为生成(generate)也是可以的。


Stringify

生成器它生成得好,可以生成出很整洁的字符串,方便我们阅读,不过在这里我们只进行字符生成,不进行排版操作,所以最后生成出来的就是一长串的挤在一行里的字符串。
在这里我们也能想到,生成器的操作就是解析器反过来,所以它大致的架构也是一个循环里套一个switch语句。
这里为了代码的美观我们也是像parse和parse_value那样将stringify和stringify_value区分开来。


#ifndef LEPT_PARSE_STRINGIFY_INIT_SIZE
#define LEPT_PARSE_STRINGIFY_INIT_SIZE 256
#endifchar* lept_stringify(const lept_value& v, size_t length) {lept_context c;assert(&v != NULL);c.stack = (char*)malloc(c.size = LEPT_PARSE_STRINGIFY_INIT_SIZE);c.top = 0;lept_stringify_value(c, v);if (length)length = c.top;PUTC(c, '\0');return c.stack;
}

这里的stringify函数的主要操作是创建一个context并为其分配一定初识内存(初始化)以及最后的在字符串尾放一个空字符

Null/Bool Stringify

case LEPT_NULL:   PUTS(c, "null", 4); break;
case LEPT_FALSE:  PUTS(c, "false", 5); break;
case LEPT_TRUE:   PUTS(c, "true", 4);break;

简单类型,不多赘述,

Number Stringify

case LEPT_NUMBER: c.top -= 32 - (sprintf((char*)lept_context_push(c, 32), "%.17g", v.u.m_num));
break;

这里的操作其实不是很美观,在对性能的极致追求上,将一些理解性的临时变量给省略了。如果换成以下的代码也许会更好理解:

  case LEPT_NUMBER:{//向context中压入32的内存(32为数字最大占用字符串大小)char* buffer = lept_context_push(c, 32);//在其中写入数据(number->string),并记录占用的字符数int length = sprintf(buffer, "%.17g", v->u.n);//栈顶移动c->top -= 32 - length;}break;

String Stringify

String的生成因为涉及到转义序列,而转义序列会用到switch,为了代码的美观,我们将string_stringify封装以下。
在stringify_value中代码如下

case LEPT_STRING: lept_stringify_string(c, v.u.m_str.s, v.u.m_str.len);
break;

string_stringify函数:

static void lept_stringify_string(lept_context& c, const char* s, size_t len) {//十六进制编码转换的常量static const char hex_digits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };size_t i, size;char* head, * p;assert(s != NULL);p = head = (char*)lept_context_push(c, size = len * 6 + 2); /* "\u00xx..." */*p++ = '"';for (i = 0; i < len; i++) {unsigned char ch = (unsigned char)s[i];switch (ch) {case '\"': *p++ = '\\'; *p++ = '\"'; break;case '\\': *p++ = '\\'; *p++ = '\\'; break;case '\b': *p++ = '\\'; *p++ = 'b';  break;case '\f': *p++ = '\\'; *p++ = 'f';  break;case '\n': *p++ = '\\'; *p++ = 'n';  break;case '\r': *p++ = '\\'; *p++ = 'r';  break;case '\t': *p++ = '\\'; *p++ = 't';  break;default://十六进制编码转换if (ch < 0x20) {*p++ = '\\'; *p++ = 'u'; *p++ = '0'; *p++ = '0';*p++ = hex_digits[ch >> 4];*p++ = hex_digits[ch & 15];}else*p++ = s[i];}}*p++ = '"';c.top -= size - (p - head);
}

Array Stringify&Object Stringify

因为二者十分相似,都递归了stringify_value,我就放一起了,object只是多一个key值的stringify

case LEPT_ARRAY:PUTC(c, '[');for (i = 0; i < v.u.m_arr.size; i++) {if (i > 0)PUTC(c, ',');lept_stringify_value(c, v.u.m_arr.e[i]);}PUTC(c, ']');break;case LEPT_OBJECT:PUTC(c, '{');for (i = 0; i < v.u.m_obj.size; i++) {if (i > 0)PUTC(c, ',');lept_stringify_string(c, v.u.m_obj.m[i].k, v.u.m_obj.m[i].klen);PUTC(c, ':');lept_stringify_value(c, v.u.m_obj.m[i].v);}PUTC(c, '}');break;

如果要进行美化的话,可以使用局部静态变量。
以下是我的美化操作:

static int num = 0;//在stringify的switch外部引入一个局部静态变量
/* ..... */
case LEPT_OBJECT:PUTC(c, '{');for (i = 0; i < v.u.m_obj.size; i++) {PUTC(c, '\n');            /* 美化操作 */for(int x = 0;x<++num;x++)/* 美化操作 */PUTC(c, '\t');lept_stringify_string(c, v.u.m_obj.m[i].k, v.u.m_obj.m[i].klen);PUTC(c, ':');lept_stringify_value(c, v.u.m_obj.m[i].v);if (i > 0)PUTC(c, ',');}PUTC(c, '\n');                 /* 美化操作 */for (int x = 0; x < --num; x++)/* 美化操作 */PUTC(c, '\t');PUTC(c, '}');break;
/* ..... */

这里主要对object进行了美化,也就是说其它的变量比如array依然是会输出在同一行。
最后可以自行进行一些测试,因为现在能够生成字符串了,自行感受以下整洁的数据结构还是很享受的一件事。

单元测试

不过该有的单元测试还是要有的

为贯彻 TDD,先写测试:

专门定义一个生成测试宏

#define TEST_ROUNDTRIP(json)\do {\lept_value v;\char* json2;\size_t length;\lept_init(&v);\EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v, json));\EXPECT_EQ_INT(LEPT_STRINGIFY_OK, lept_stringify(&v, &json2, &length));\EXPECT_EQ_STRING(json, json2, length);\lept_free(&v);\free(json2);\} while(0)static void test_stringify_number() {TEST_ROUNDTRIP("0");TEST_ROUNDTRIP("-0");TEST_ROUNDTRIP("1");TEST_ROUNDTRIP("-1");TEST_ROUNDTRIP("1.5");TEST_ROUNDTRIP("-1.5");TEST_ROUNDTRIP("3.25");TEST_ROUNDTRIP("1e+20");TEST_ROUNDTRIP("1.234e+20");TEST_ROUNDTRIP("1.234e-20");TEST_ROUNDTRIP("1.0000000000000002"); /* the smallest number > 1 */TEST_ROUNDTRIP("4.9406564584124654e-324"); /* minimum denormal */TEST_ROUNDTRIP("-4.9406564584124654e-324");TEST_ROUNDTRIP("2.2250738585072009e-308");  /* Max subnormal double */TEST_ROUNDTRIP("-2.2250738585072009e-308");TEST_ROUNDTRIP("2.2250738585072014e-308");  /* Min normal positive double */TEST_ROUNDTRIP("-2.2250738585072014e-308");TEST_ROUNDTRIP("1.7976931348623157e+308");  /* Max double */TEST_ROUNDTRIP("-1.7976931348623157e+308");}static void test_stringify_string() {TEST_ROUNDTRIP("\"\"");TEST_ROUNDTRIP("\"Hello\"");TEST_ROUNDTRIP("\"Hello\\nWorld\"");TEST_ROUNDTRIP("\"\\\" \\\\ / \\b \\f \\n \\r \\t\"");TEST_ROUNDTRIP("\"Hello\\u0000World\"");}static void test_stringify_array() {TEST_ROUNDTRIP("[]");TEST_ROUNDTRIP("[null,false,true,123,\"abc\",[1,2,3]]");}static void test_stringify_object(){TEST_ROUNDTRIP("{}");TEST_ROUNDTRIP("{\"n\":null,\"f\":false,\"t\":true,\"i\":123,\"s\":\"abc\",\"a\":[1,2,3],\"o\":{\"1\":1,\"2\":2,\"3\":3}}");}static void test_stringify() {TEST_ROUNDTRIP("null");TEST_ROUNDTRIP("false");TEST_ROUNDTRIP("true");test_stringify_number();test_stringify_string();test_stringify_array();test_stringify_object();}

以上就是生成器的编写。之后讲以下所有的api,那么整个json的复习(对于我自己)就结束了。之后就要进入下一个项目的学习了

我走在一条未知的道路上,我所能做的就是走下去,直到路口或者尽头


lept_json Github:https://github.com/miloyip/json-tutorial

本人流星画魂第七次在csdn上做笔记,有什么错误或者是需要改进的地方请即时提出
我只是一个对编程感兴趣的人,但懒得要死,学得又不认真,希望读者能骂就骂两句,真的太懒了

lept_json的学习之stringify相关推荐

  1. lept_json的学习之JSON

    lept_json库的学习1 从两个星期前开始,在github上跟着叶劲峰老师的lept_json学习了一遍,现在来回顾一下整个过程,做些笔记之类的. 本人的记录风格是废话一大堆,所以不爱看的可以骂我 ...

  2. [转] 你不知道的 JSON.stringify() 的威力

    原文地址: https://github.com/NieZhuZhu/Blog/issues/1 前言 其实有很多有用的东西,当时学习了,也记住了,但是时间久了就是记不住,所以导致在日常开发中总是想不 ...

  3. 常见前端数据格式转换

    开发的过程当中遇到这样一个处理数据的需求: 场景: const todayILearn = {_id: 1,content: '今天学习 JSON.stringify(),我很开心!',created ...

  4. JSON.stringfy()详解

    前言 其实有很多有用的东西,当时学习了,也记住了,但是时间久了就是记不住,所以导致在日常开发中总是想不起来原来这个东西可以这么用,而去选择了更加复杂和麻烦的方式.其实我们日常学习的知识就是拿来用的,即 ...

  5. JSON学习笔记(五)- JSON.stringify()

    JSON.stringify() JSON 通常用于与服务端交换数据. 在向服务器发送数据时一般是字符串. 我们可以使用 JSON.stringify() 方法将 JavaScript 对象转换为字符 ...

  6. Auto.js学习笔记10:实例化自定义对象,在子线程使用JSON.stringify()方法导致报错(已解决)

    申明本人使用的autojs是4.1.1版本 JSON.stringify()使用导致autojs软件直接奔溃退出. 报错核心局部代码 var sendInfoObj = { //对象areaCode ...

  7. vue vue-router vuex element-ui axios 的学习笔记(七)完善登录注册

    现在我们已经能够在服务器环境下完成注册操作了 登录功能 login.vue <template><el-main><el-form :model="LoginF ...

  8. EF 4.1+MVC3+Jquery Ajax+Json.Net+JqueryUI+IUnitOfWork+Repository 学习DEMO(暂停更新)

    学习项目进行中,持续更新. SyntaxHighlighter貌似在2011wlw里报错,无法着色. EF记得在我搞Linq2Sql不久就放出声音出来了,说有多么多么好. 记得早先版本里尝鲜的时候我一 ...

  9. 【转】Angular学习总结--很详细的教程

    *这篇文章是转来的,做了自己的一点修改,排版.原始出处不明,如涉及原博主版权问题,请及时告知,我将会立即删除*. 1 前言 前端技术的发展是如此之快,各种优秀技术.优秀框架的出现简直让人目不暇接,紧跟 ...

  10. nodejs学习资料

    2019独角兽企业重金招聘Python工程师标准>>> NodeJS基础 什么是NodeJS JS是脚本语言,脚本语言都需要一个解析器才能运行.对于写在HTML页面里的JS,浏览器充 ...

最新文章

  1. 写一个android图表框架1
  2. sqlserver快速查找所有存储过程中是否包含某字符
  3. innobackupex参数说明
  4. TypeScript内置对象
  5. 新装Ubuntu 11.04有感
  6. CentOS启动时报错修复
  7. 旁边一位员工天天跟别人聊天,主管都不敢管,那你当什么主管
  8. 计算机视觉-OpenCV(银行卡号识别)
  9. 不禁网页的浏览器_什么浏览器不屏蔽网站
  10. 给网站添加优质内容的25种方式
  11. python中if语句的实例_python的if语句里怎样写两个条件
  12. 我的自定义知乎首页及问题页的样子
  13. 一入IT深似海,从此都是考证人~耗时,耗力,耗财,耗头发考过的证书 千万不要忘了延续~
  14. 计算机打开查看方式默认是什么样,如何设置电脑文件夹默认查看方式
  15. 热血传奇手游IOS辅助哪个好呢?
  16. Springboot 整合Retry 实现重试机制
  17. B站狂神 JavaWeb 1-6
  18. 数学归纳法的原理是什么?
  19. java 企业网站源码 后台 springmvc SSM 前台 静态化 代码生成器
  20. 我爱背单词 - 0301

热门文章

  1. 华为交换机做qos案例_华为交换机 01-08 QoS
  2. java 传输 udp_java UDP传输
  3. QT学习笔记——06-Day15_C++_QT
  4. oracle 数据库官网下载流程
  5. coreseek mysql_centos+php+coreseek+sphinx+mysql之一coreseek安装篇
  6. 高中计算机编程软件vb,高中年级VB程序设计全套教案.doc
  7. 汇编语言程序设计实验三
  8. HTML+CSS+JS生日祝福网页在线制作(多种款式)
  9. 网吧服务器ip地址修改,详解修改BXP服务器IP地址的方法
  10. 登录验证----滑块/拼图碎片/随机num