从零开始的JSON教程学习

2016-11-13  本文已影响0人  王昕业

此文为学习知乎上Milo的编程”专栏所载的从零开始的JSON教程所作的学习笔记,同时也是学习简书的Markdown语法的时间,因为一直想找一个能做学习笔记的网站,并且由于笔记的很多内容涉及代码块,支持Markdown语法的简书似乎是个不错的选择。同时希望自己能够坚持,持续学习。(由于是学习笔记,大量的内容来自于专栏,专栏作者为Milo Yip,特此说明)

一、启程

1. JSON是什么?

JSON是一种用于数据交换的文本格式,具有类似功能的语言有XML、YAML等等,但JSON的语法最简单。一个简单的例子的JSON文本的例子:

 {
    "title": "Design Patterns",
    "subtitle": "Elements of Reusable Object-Oriented Software",
    "author": [
        "Erich Gamma",
        "Richard Helm",
        "Ralph Johnson",
        "John Vlissides"
    ],
    "year": 2009,
    "weight": 1.8,
    "hardcover": true,
    "publisher": {
        "Company": "Pearson Education",
        "Country": "India"
    },
    "website": null
}

由此可以看见,一个JSON对象的表示是用{...},JSON的数据类型有六种数据类型:

Type Format
null null
booleab true or false
number 浮点数
string "Design Patterns"
array [...]
objecte {}

可以发现一个object的数据类型可以是另一个object,这说明JSON是一种树状的结构。一个JSON库应当提供的功能包括:

(事实上,对于access不是特别能理解,希望在感悟下)

2. 编译环境配置

pass
此处的内容之后再补充,对于编译环境的搭建CMake、Git的使用还是要抽时间本地使用下

3.头文件与API设计
#ifndef LEPTJSON_H__
#define LEPTJSON_H__
/* 此处写入头文件内容,如各种声明 */
#endif /*LEPTJSON_H__*/

一般以_H__作为后缀,并且要保证唯一。

typedef enum { 
        LEPT_NULL, 
        LEPT_FALSE,  
        LEPT_TRUE,
        LEPT_NUMBER, 
        LEPT_STRING,
        LEPT_ARRAY, 
        LEPT_OBJECT
}  lept_type;

一些作者提到的注意点:C语言没有明明空间的概念,因此需要保证标识符的唯一性,因此一般用项目名称的简写做前缀,枚举值用大写而函数和类型定义用小写

typedef struct {
lept_type type;
} lept_value;
typedef enum {
         LEPT_PARSE_OK , 
         LEPT_PARSE_EXPECT_VALUE,
         LEPT_PARSE_INVALID_VALUE,
         LEPT_PARSE_ROOT_NOT_SINGULAR
} lept_parse_result;      
/*API-1,解析一个json,即parse,结果填入一个lept_value。注意const的用法是保证json不会被改动*/
lept_parse_result lept_parse(lept_value &v, const char* json);       
/*API-2,获取结果,即access,注意const 以及指针的使用(防止对象拷贝)*/
lept_type lept_get_tyepe(const lept_value* v);
json_text = ws value ws
ws = *(%0x20, %x0x09, %0x0A, %x0D)   ------*  表示零或多个
value = 'null' / 'false' / 'true'    -----/ 表示其中一个

前面已经提到了lept_parse的返回类型,下面表示本单元语法下分别代表的含义:

typedef enum {
         LEPT_PARSE_OK ,         //解析成功
         LEPT_PARSE_EXPECT_VALUE,  //JSON串只有空白
         LEPT_PARSE_INVALID_VALUE,
         LEPT_PARSE_ROOT_NOT_SINGULAR //一个值、空白后还有其他值
} lept_parse_result;    

TTD是先写测试在写开发,优点是实现刚好满足测试的代码,且容易把控质量。本项目提供了一个测试框架。以下做代码学习。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "leptjson.h"

static int main_ret = 0;
static int test_count = 0;
static int test_pass = 0;
//注意宏分多行写的技巧 
//注意fprintf和printf区别:注意format为什么可以这么写:类似于char * = “%d”“%d”这样写没毛病,注意stderr
//printf是向stdout,fprintf是向FILE*输出,stderr和stdout等都是该类型,
//stderr时另一个输
//出流
#define EXPECT_EQ_BASE(equality, expect, actual, format) \
    do {\
        test_count++;\
        if (equality)\
            test_pass++;\
        else {\
            fprintf(stderr, "%s:%d: expect: " format " actual: " format "\n", __FILE__, __LINE__, expect, actual);\
            main_ret = 1;\
        }\
    } while(0)

#define EXPECT_EQ_INT(expect, actual) EXPECT_EQ_BASE((expect) == (actual), expect, actual, "%d")

static void test_parse_null() {
    lept_value v;
    v.type = LEPT_TRUE;
    EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v, "null"));
    EXPECT_EQ_INT(LEPT_NULL, lept_get_type(&v));
}

/* ... */

static void test_parse() {
    test_parse_null();
    /* ... */
}

int main() {
    test_parse();
    printf("%d/%d (%3.2f%%) passed\n", test_pass, test_count, test_pass * 100.0 / test_count);
    return main_ret;
}
4. 课后习题

其他的就不关注 了,有一点有意思的要注意下,当有一个函数申明为static后意味这个函数只在当前编译单元使用

一、启程

1. JSON是什么?
上一篇下一篇

猜你喜欢

热点阅读