日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

lept_json的学习之stringify

發布時間:2023/12/10 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 lept_json的学习之stringify 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。