来自

从零开始的 JSON 库教程
从零开始教授如何写一个符合标准的 C 语言 JSON 库
作者 Milo Yip

https://zhuanlan.zhihu.com/json-tutorial

根据第一课教程 自己重新编写 做了一点修改 加深学习印象

//JsonParse.h
#pragma once
#include "JsonStruct.h"
#include <assert.h> void DEFParseWhitespace(MyJsonStruct& js)
{
while (js.jsonStr[js.index] == ' ' ||
js.jsonStr[js.index] == '\r' ||
js.jsonStr[js.index] == '\n') {
js.index++;
}
} DefParseResult DEFParseNull(MyJsonStruct& js)
{
assert(js.jsonStr[js.index] = 'n');
if (js.jsonStr[js.index + 1] != 'u' ||
js.jsonStr[js.index+2] != 'l' ||
js.jsonStr[js.index+3] != 'l') {
return DEF_PARSE_INVALID_VALUE;
}
js.index += 4;
js.type = DEF_NULL;
return DEF_PARSE_OK;
} DefParseResult DEFParseValue(MyJsonStruct& js)
{
switch (js.jsonStr[js.index]){
case 'n':return DEFParseNull(js);
case '\0':return DEF_PARSE_EXPECT_VALUE;
default:return DEF_PARSE_INVALID_VALUE;
}
} DefParseType GetParseType(MyJsonStruct& js)
{
return js.type;
} void ResetJsonStruct(const char* jsonBuf, MyJsonStruct& js)
{
js.jsonStr = jsonBuf;
js.index = 0;
js.type = DEF_NONE;
} MyJsonStruct InitJsonStruct(char* jsonBuf)
{
MyJsonStruct jsonStruct;
ResetJsonStruct(jsonBuf, jsonStruct);
return jsonStruct;
} DefParseResult DEFParse(MyJsonStruct& jsonStruct)
{
DefParseResult ret; DEFParseWhitespace(jsonStruct); if ((ret = DEFParseValue(jsonStruct)) == DEF_PARSE_OK) {
DEFParseWhitespace(jsonStruct);
if (jsonStruct.index < jsonStruct.jsonStr.size()) {
ret = DEF_PARSE_ROOT_NOT_SINGULAR;
jsonStruct.type = DEF_NONE;
} }
return ret;
}

  

//JsonStruct.h
#pragma once
#include <string> enum DefParseType {
DEF_NONE,
DEF_NULL,
DEF_FALSE,
DEF_TRUE,
DEF_NUMBER,
DEF_STRING,
DEF_ARRAY,
DEF_OBJECT
}; struct MyJsonStruct {
std::string jsonStr;
size_t index;
DefParseType type;
}; enum DefParseResult{
DEF_PARSE_OK = 0,
DEF_PARSE_EXPECT_VALUE,
DEF_PARSE_INVALID_VALUE,
DEF_PARSE_ROOT_NOT_SINGULAR
};

  

//MyTestUnit.h
#pragma once
#include <iostream> class MyTestClass {
static size_t testCount_;
static size_t testPass_;
public:
template<typename E,typename A>
bool ExceptEqual(E e, A a)
{
testCount_++;
if (e == a){
testPass_++;
return true;
}
return false;
} void PrintResult(){
std::cout << testPass_ << "/" << testCount_ << "\t" << "("<<(testPass_ * 100.0 / testCount_) << "%)" << " passed." << std::endl;
}
};
size_t MyTestClass::testCount_ = 0;
size_t MyTestClass::testPass_ = 0; #define ERROR_PRINT(expect,actual) \
std::cerr << __FILE__ <<":"<< __LINE__ << "\r\nexpect: " << expect << " actual: " << actual << std::endl; #define EXCEPT_EQ(expect, actual) \
do{ \
MyTestClass TEST; \
if(!TEST.ExceptEqual(expect, actual)){ \
ERROR_PRINT(expect,actual) \
} \
}while(0) #define PRINT_TEST_RESULT() \
do{ \
MyTestClass TEST; \
TEST.PrintResult(); \
}while(0)

  

// MyJson.cpp : 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include "JsonParse.h"
#include <iostream>
#include "MyTestUnit.h" int main()
{
MyJsonStruct js =InitJsonStruct("null");
EXCEPT_EQ(DEF_PARSE_OK, DEFParse(js));
EXCEPT_EQ(DEF_NULL, GetParseType(js)); ResetJsonStruct("", js);
EXCEPT_EQ(DEF_PARSE_EXPECT_VALUE, DEFParse(js));
EXCEPT_EQ(DEF_NONE, GetParseType(js)); ResetJsonStruct(" ", js);
EXCEPT_EQ(DEF_PARSE_EXPECT_VALUE, DEFParse(js));
EXCEPT_EQ(DEF_NONE, GetParseType(js)); ResetJsonStruct("nul", js);
EXCEPT_EQ(DEF_PARSE_INVALID_VALUE, DEFParse(js));
EXCEPT_EQ(DEF_NONE, GetParseType(js)); ResetJsonStruct("?", js);
EXCEPT_EQ(DEF_PARSE_INVALID_VALUE, DEFParse(js));
EXCEPT_EQ(DEF_NONE, GetParseType(js)); ResetJsonStruct("null x", js);
EXCEPT_EQ(DEF_PARSE_ROOT_NOT_SINGULAR, DEFParse(js));
EXCEPT_EQ(DEF_NONE, GetParseType(js)); PRINT_TEST_RESULT();
return 0;
}

  测试效果

12/12 (100%) passed.
请按任意键继续. . .

状态机学习(三)解析JSON1的更多相关文章

  1. Java开发学习(三十六)----SpringBoot三种配置文件解析

    一. 配置文件格式 我们现在启动服务器默认的端口号是 8080,访问路径可以书写为 http://localhost:8080/books/1 在线上环境我们还是希望将端口号改为 80,这样在访问的时 ...

  2. HTTP学习三:HTTPS

    HTTP学习三:HTTPS 1 HTTP安全问题 HTTP1.0/1.1在网络中是明文传输的,因此会被黑客进行攻击. 1.1 窃取数据 因为HTTP1.0/1.1是明文的,黑客很容易获得用户的重要数据 ...

  3. DjangoRestFramework学习三之认证组件、权限组件、频率组件、url注册器、响应器、分页组件

    DjangoRestFramework学习三之认证组件.权限组件.频率组件.url注册器.响应器.分页组件   本节目录 一 认证组件 二 权限组件 三 频率组件 四 URL注册器 五 响应器 六 分 ...

  4. 深入学习Python解析并解密PDF文件内容的方法

    前面学习了解析PDF文档,并写入文档的知识,那篇文章的名字为深入学习Python解析并读取PDF文件内容的方法. 链接如下:https://www.cnblogs.com/wj-1314/p/9429 ...

  5. day91 DjangoRestFramework学习三之认证组件、权限组件、频率组件、url注册器、响应器、分页组件

    DjangoRestFramework学习三之认证组件.权限组件.频率组件.url注册器.响应器.分页组件   本节目录 一 认证组件 二 权限组件 三 频率组件 四 URL注册器 五 响应器 六 分 ...

  6. docker深入学习三

    docker学习三:network docker支持容器之间的网络通信,docker的网络通信方式有以下五种: bridge docker 默认的网络驱动,如果不指定网络驱动,docker就会创建一个 ...

  7. day 89 DjangoRestFramework学习三之认证组件、权限组件、频率组件、url注册器、响应器、分页组件

    DjangoRestFramework学习三之认证组件.权限组件.频率组件.url注册器.响应器.分页组件   本节目录 一 认证组件 二 权限组件 三 频率组件 四 URL注册器 五 响应器 六 分 ...

  8. day 82 Vue学习三之vue组件

      Vue学习三之vue组件   本节目录 一 什么是组件 二 v-model双向数据绑定 三 组件基础 四 父子组件传值 五 平行组件传值 六 xxx 七 xxx 八 xxx 一 什么是组件 首先给 ...

  9. ElasticSearch7.3学习(三十二)----logstash三大插件(input、filter、output)及其综合示例

    1. Logstash输入插件 1.1 input介绍 logstash支持很多数据源,比如说file,http,jdbc,s3等等 图片上面只是一少部分.详情见网址:https://www.elas ...

  10. Java开发学习(三十七)----SpringBoot多环境配置及配置文件分类

    一.多环境配置 在工作中,对于开发环境.测试环境.生产环境的配置肯定都不相同,比如我们开发阶段会在自己的电脑上安装 mysql ,连接自己电脑上的 mysql 即可,但是项目开发完毕后要上线就需要该配 ...

随机推荐

  1. asp.net之发送邮件2

    public void SendMail(string from, string to, List<string> cc, string subject, string body) { M ...

  2. Android学习路-Android Studio的工程目录

    说明:下图为一个app的工程目录,如果在res下随便建立文件夹(比如test等名字)是不会显示在工程内的

  3. sys系统用户长时间未登录导致密码过期

    ORA-28001: the password has expired (DBD ERROR: OCISessionBegin) 问题描述:当登陆em时使用sys帐号登陆进去后,数据库实例提示ORA- ...

  4. verilog task2

    1.问题:串口的发送和接收 系统时钟50Mhz,波特率119200.系统时钟计数约2604个,才是一位数据的传输时间. 模拟接收的任务函数rx_data_task():LSB first task r ...

  5. NumPy IO

    NumPy IO Numpy 可以读写磁盘上的文本数据或二进制数据. NumPy 为 ndarray 对象引入了一个简单的文件格式:npy. npy 文件用于存储重建 ndarray 所需的数据.图形 ...

  6. TOJ 4976: 新生数(深搜)

    传送门:http://acm.tzc.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=4976 时间限制(普通/Java): ...

  7. PHP简单工厂模式、工厂方法模式和抽象工厂模式比较

    PHP工厂模式概念:工厂模式是一种类,它具有为您创建对象的某些方法.您可以使用工厂类创建对象,而不直接使用 new.这样,如果您想要更改所创建的对象类型,只需更改该工厂即可.使用该工厂的所有代码会自动 ...

  8. mac item2 ssh

    一.常规ssh登录流程 ssh登陆有三个参数,主机名,用户名,用户密码,流程都是一样. 1.ssh 用户名@主机名 2.返回包含(yes/no)的字符串,此时输入 “yes" 3.然后再返回 ...

  9. swift - 加速器/摇一摇功能

    import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoa ...

  10. String.format的用法

    有些时候,对于一些东西,不是没有简单的方法,而是我们没有接触到过 String.format();即创建格式化的字符串,里面有很多的通配使用符号,我这里说一下我接触到的,以后接触到其他的再填坑 它的内 ...