C语言实现手写JSON解析的方法详解

目录
  • 什么是JSON
  • JSON支持的数据类型
  • JSON语法规则
  • JSON的解析
  • JSON基本语法
  • 编写解析器
    • 头文件
    • 实现文件

什么是JSON

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,用来传输属性值或者序列性的值组成的数据对象。

JSON是JavaScript的一个子集。

具有良好的可读性和便于快速编写的特性。

JSON是独立于语言的文本格式,并且采用了类似C语言家族的一些习惯。

JSON数据格式与语言无关,是目前网络中主流的数据传输格式之一,使用率几乎为99%。

JSON支持的数据类型

JSON里面的数据以一种键值对的方式存在,即“key”:“value” 类型可以是数据类型中的任意一种:

JSON语法规则

JSON的语法规则非常简单,使用

大括号——{}

中括号——[]

逗号——,

冒号——:

双引号——“” (一般可以不需要)

JSON的解析

在解析JSON是我们会遇到两种情况,其一是解析大括号——{}类型,其二是解析中括号类型——[],以及这两种类型的组合模式。

JSON基本语法

对象类型(Object)

{
    "name" : "佩奇" ,
    "age" : "8"
}

数组类型(Array)

[
"喜羊羊","懒羊羊",5,true,null
]

对象组合形

{
    "name" : "佩奇" ,
    "age" : "8",
    "friend" :[{"name" : " 喜羊羊 " , "age" : "5"} , {"name" : " 懒羊羊 " , "age" : "6"}]
    //对象类型嵌套数组类型,数组类型嵌套对象类型
}

数组组合型

[ [{"name" : "佩奇" ,"age" : "8"},{"name" : "佩奇" ,"age" : "8"}],[{},{}]]

编写解析器

头文件

//
// Created by huanmin on 2022/9/15.
//

#ifndef STUDY_JSON_H
#define STUDY_JSON_H
#include "../util/str_util.h"
#include <stdio.h>
#include "charhashmap.h"
#include "charlist.h"
#include "../util/assertmy.h"
static char *str_to_json_placeholder(char *string, CharHashMap *map, CharHashMap *list);
static char *querySubstitute(char *string, CharHashMap *map, CharHashMap *list);
BOOL str_is_json(char *string);
CharList *str_to_json_array(char *array);
CharHashMap *str_to_json_map(char *dict);
char *map_to_json_str(CharHashMap *pMap);
char *array_to_json_str(CharList *pCharlist);
BOOL str_is_map(char *str);
BOOL str_is_array(char *str);
#endif //STUDY_JSON_H

实现文件

//
// Created by huanmin on 2022/9/15.
//

#include "json.h"

//转换字符串为JSON_先进行占位符替换
static char *str_to_json_placeholder(char *string, CharHashMap *map, CharHashMap *list) {
    //判断是否有[],如果有那么提取出来,并且将位置上的内容替换为 @arri
    int zi = 0;
    int start = -1;
    while ((start = str_find(string, "[")) != -1) {
        int length = str_length(string);
        int jilu = 0;
        int end = -1;
        for (int i = start; i < length; ++i) {
            if (string[i] == '[') {
                jilu++;
            }
            if (string[i] == ']') {
                jilu--;
                if (jilu == 0) {
                    end = i;
                    break;
                }
            }
        }
        char *arr_str = str_substring(string, start, end);
        char *append = str_concat(3, "@arr", int_to_str(zi), "@");
        putCharHashMap(list, append, arr_str);
        string = str_replace(string, arr_str, append);
        zi++;
    }
    zi = 0;
    start = -1;
    //判断是否有{},如果有那么提取出来, 并且将位置上的内容替换为@mapi
    while ((start = str_find(string, "{")) != -1) {
        int length = str_length(string);
        int jilu = 0;
        int end = -1;
        for (int i = start; i < length; ++i) {
            if (string[i] == '{') {
                jilu++;
            }
            if (string[i] == '}') {
                jilu--;
                if (jilu == 0) {
                    end = i;
                    break;
                }
            }

        }

        char *map_str = str_substring(string, start, end);
        char *append = str_concat(3, "@map", int_to_str(zi), "@");
        putCharHashMap(map, append, map_str);
        string = str_replace(string, map_str, append);
        zi++;
    }
    return string;
}

static char *querySubstitute(char *string, CharHashMap *map, CharHashMap *list) {
    char *str = string;
    int start = -1;
    //替换
    if (str_start_with(string, "@map")) {
        while ((start = str_find(str, "@map")) != -1) {
            int end = str_find_n(str, "@", start + 1, str_length(str));
            char *substring = str_substring(str, start, end);
            str = (char *) getCharHashMap(map, substring);
        }
    } else if (str_start_with(string, "@arr")) {
        //替换参数为原来的值
        while ((start = str_find(str, "@arr")) != -1) {
            int end = str_find_n(str, "@", start + 1, str_length(str));
            char *substring = str_substring(str, start, end);
            str = (char *) getCharHashMap(list, substring);
        }
    }
    start = -1;
    //判断是否还包含@map或者@arr,如果有那么就继续替换
    while ((start = str_find(str, "@map")) != -1 || (start = str_find(str, "@arr")) != -1) {
        //截取所有的@map@和@arr@,并且将其替换为原来的字符串
        CharList *pCharlist = createCharList(10);
        while ((str_find_n(str, "@map", start, str_length(str))) != -1 ||
               (str_find_n(str, "@arr", start, str_length(str))) != -1) {
            int end = str_find_n(str, "@", start + 1, str_length(str));
            char *substring = str_substring(str, start, end);
            addCharList(pCharlist, substring);
            start = end;
        }
        CharListIterator *pIterator = createCharListIterator(pCharlist);
        while (hasNextCharListIterator(pIterator)) {
            char *key = nextCharListIterator(pIterator);
            if (str_start_with(key, "@map")) {
                char *value = (char *) getCharHashMap(map, key);
                str = str_replace(str, key, value);
            } else if (str_start_with(key, "@arr")) {
                char *value = (char *) getCharHashMap(list, key);
                str = str_replace(str, key, value);
            }
        }
    }
    return str;
}

//将字符串数组格式[1,2,3]或者[{a:b,c:d},{a:b,c:d}]转换为List  ,(没有任何格式验证,全靠自己规范编写)
CharList *str_to_json_array(char *array) {
    if (array == NULL || str_length(array) == 0) {
        return NULL;
    }
    char *trim = str_trim(array);
    char *string = str_substring(trim, 1, str_length(trim) - 2);
    CharHashMap *map = createCharHashMap(10);
    CharHashMap *list = createCharHashMap(10);
    char *string1 = str_to_json_placeholder(string, map, list);
    CharList *pCharlist = str_split(string1, ",");
    for (int i = 0; i < pCharlist->len; ++i) {
        char *v = pCharlist->str[i];
        pCharlist->str[i] = querySubstitute(v, map, list);
    }
    return pCharlist;
}

//将json对象字符串{a:b,c:d},转换为hashMap  ,(没有任何格式验证,全靠自己规范编写)
CharHashMap *str_to_json_map(char *dict) {
    if (dict == NULL || str_length(dict) == 0) {
        return NULL;
    }
    char *trim = str_trim(dict);
    char *string = str_substring(trim, 1, str_length(trim) - 2);
    CharHashMap *map = createCharHashMap(10);
    CharHashMap *list = createCharHashMap(10);
    char *string1 = str_to_json_placeholder(string, map, list);
    CharList *pCharlist = str_split(string1, ",");
    int str_len = pCharlist->len;
    if (str_len == 0) {
        return NULL;
    }
    //分割key和value
    CharHashMap *pMap = createCharHashMap(str_len);
    for (int i = 0; i < str_len; i++) {
        char *str = pCharlist->str[i];
        CharList *pList = str_split(str, ":");
        char *key = str_trim(pList->str[0]);
        char *value = str_trim(pList->str[1]);
        putCharHashMap(pMap, key, querySubstitute(value, map, list));
    }
    return pMap;
}

//将hashMap转换为json对象{a:b,c:d,v:[1,2],f:{a:b,c:d}} ,(没有任何格式验证,全靠自己规范编写)
char *map_to_json_str(CharHashMap *pMap) {
    if (pMap == NULL) {
        return NULL;
    }
    char *string = str_create("{");
    int len = pMap->size;
    //创建迭代器
    CharHashMapIterator *pIterator = createCharHashMapIterator(pMap);
    while (hasNextCharHashMapIterator(pIterator)) {
        CharKvLinkedNode *pNode = nextCharHashMapIterator(pIterator);
        string = str_append(string, pNode->key);
        string = str_append(string, ":");
        string = str_append(string, pNode->value);
        if (len != 1) {
            string = str_append(string, ",");
        }
        len--;
    }
    string = str_append(string, "}");
    return string;
}

//将CharList转换为json数组格式[1,2,[1,2,3]]或者[{},{}] ,(没有任何格式验证,全靠自己规范编写)
char *array_to_json_str(CharList *pCharlist) {
    if (pCharlist == NULL) {
        return NULL;
    }
    char *string = str_create("[");
    for (int i = 0; i < pCharlist->len; ++i) {
        string = str_append(string, pCharlist->str[i]);
        if (i != pCharlist->len - 1) {
            string = str_append(string, ",");
        }
    }
    string = str_append(string, "]");
    return string;
}

//判断是否是json对象
BOOL str_is_map(char *str) {
    if (str == NULL) {
        return FALSE;
    }
    if (str_length(str) < 2) {
        return FALSE;
    }
    if (str_start_with(str, "{") && str_end_with(str, "}")) {
        return TRUE;
    }
    return FALSE;
}

//判断是否是数组
BOOL str_is_array(char *str) {
    if (str == NULL) {
        return FALSE;
    }
    if (str_length(str) < 2) {
        return FALSE;
    }
    if (str_start_with(str, "[") && str_end_with(str, "]")) {
        return TRUE;
    }
    return FALSE;
}

到此这篇关于C语言实现手写JSON解析的方法详解的文章就介绍到这了,更多相关C语言 JSON解析内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++使用jsoncpp解析json的方法示例

    前言: 曾经一段时间XML成为互联网业界内的数据传输格式标准,但有人对XML提出了质疑,认为XML数据格式比较繁杂,冗长等,于是提出了一种新的表示格式-JSON. 对于JSON格式,在此就不作详细的说明了,下面主要讨论下C++解析json文件的工具-Jsoncpp的使用. JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,和xml类似,本文主要对VS2008中使用Jsoncpp解析json的方法做一下记录. Jsoncpp是个跨平台的开源库,下载地址:

  • C/C++中CJSON的使用(创建与解析JSON数据)

    目录 一.cJSON介绍 二.JSON简介.语法介绍 2.1 JSON是什么? 2.2 JSON语法介绍 三.cJSON创建简单JSON数据并解析 3.1 新建工程 3.2 创建JSON数据 3.3 解析JSON数据 四.cJSON创建嵌套的对象数据 4.1 创建json数据 4.2 解析JSON数据 五.cJSON带数组的JSON数据 5.1 创建json数据 5.2 解析JSON数据 一.cJSON介绍 cJSON 是一个超轻巧,携带方便,单文件,可以作为 ANSI-C 标准的 JSON 解

  • C++解析Json的方法详解【jsoncpp】

    本文实例讲述了C++解析Json的方法.分享给大家供大家参考,具体如下: JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,和xml类似,本文主要对VS2008中使用Jsoncpp解析json的方法做一下记录. Jsoncpp是个跨平台的开源库,下载地址:http://sourceforge.net/projects/jsoncpp/,我下载的是v0.5.0,压缩包大约104K. 方法一:使用Jsoncpp生成的lib文件 解压上面下载的Jsoncpp

  • C++使用jsoncpp库解析Json

    前言 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,和xml类似,本文主要对VS2008中使用Jsoncpp解析json的方法做一下记录. Jsoncpp是个跨平台的开源库,下载地址:http://sourceforge.net/projects/jsoncpp/. 方法一:使用Jsoncpp生成的lib文件 解压上面下载的Jsoncpp文件,在jsoncpp-src-0.5.0/makefiles/vs71目录里找到jsoncpp.sln,用VS

  • C++构造和解析Json的使用示例

    概述 JSON是一种轻量级的数据交互格式,易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率,实际项目中经常用到,相比xml有很多优点,问问度娘,优点一箩筐. 第三方库 json解析选用jsoncpp作为第三方库,jsoncpp使用广泛,c++开发首选. jsoncpp目前已经托管到了github上,地址:https://github.com/open-source-parsers/jsoncpp 使用 使用c++进行构造json和解析json,选用vs2010作为IDE.工程

  • C++使用cjson操作Json格式文件(创建、插入、解析、修改、删除)

    目录 为什么要学习解析Json文件? 一.准备cJSON开源库 二.cJSON介绍 三.封装Json 四.解析Json 五.修改Json 六.删除Json 七.全部代码 八.总结 为什么要学习解析Json文件? 工作需要呗! 最近在工作项目中,有需求是需要进行解析Json字符串的,但是我只会使用QT去解析Json,且主管规定要使用C/C++语言去解析,说是为了方便移植到其他项目中进行使用… 没办法,只能硬着头皮,在网上找找有没有什么解析Json的开源库是C/C++可以使用的.找了许多,网上也提供

  • C语言实现手写JSON解析的方法详解

    目录 什么是JSON JSON支持的数据类型 JSON语法规则 JSON的解析 JSON基本语法 编写解析器 头文件 实现文件 什么是JSON JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,用来传输属性值或者序列性的值组成的数据对象. JSON是JavaScript的一个子集. 具有良好的可读性和便于快速编写的特性. JSON是独立于语言的文本格式,并且采用了类似C语言家族的一些习惯. JSON数据格式与语言无关,是目前网络中主流的数据传输格式之一,

  • Go语言实现JSON解析的方法详解

    目录 1.json序列化 2.Json反序列化为结构体对象 3.Json反序列化为map类型 4.Tag的使用 在日常项目中,使用Json格式进行数据封装是比较常见的操作,看一下golang怎么实现. 1.json序列化 将json字符串转为go语言结构体对象. package main import ( "encoding/json" "errors" "fmt" ) var parseJsonError = errors.New("

  • C语言实现手写Map(全功能)的示例代码

    目录 为啥需要Map结构 主流Map结构 数组+链表的Map 结构 hash函数 创建Map集合 扩容基数 扩容Map集合 给Map集合添加元素 打印Map集合 获取Map集合中的指定元素 判断键是否存在 判断值是否存在 删除Map集合中的指定元素 修改Map集合中的指定元素 迭代器 获取所有的key 获取所有的value 复制一个Map 将一个map集合合并到另一个map集合里 合并两个Map集合,返回一个新的Map集合 差集 交集 补集 并集 清除Map 为啥需要Map结构 假设,数据很少,

  • C语言实现手写Map(数组+链表+红黑树)的示例代码

    目录 要求 结构 红黑树和链表转换策略 hash 使用 要求 需要准备数组集合(List) 数据结构 需要准备单向链表(Linked) 数据结构 需要准备红黑树(Rbtree)数据结构 需要准备红黑树和链表适配策略(文章内部提供,可以自行参考) 建议先去阅读我博客这篇文章C语言-手写Map(数组+链表)(全功能)有助于理解 hashmap使用红黑树的原因是: 当某个节点值过多的时候那么链表就会非常长,这样搜索的时候查询速度就是O(N) 线性查询了,为了避免这个问题我们使用了红黑树,当链表长度大于

  • 利用FlubuCore用C#来写DevOps脚本的方法详解

    前言 随着近些年微服务的流行,有越来越多的开发者和团队所采纳和使用,它的确提供了很多的优势也解决了很多的问题,但是我们也知道也并不是银弹,提供优势的同时它也给我们的开发人员和团队也带来了很多的挑战. 为了迎接或者采用这些新技术,开发团队需要更加注重一些流程或工具的使用,这样才能更好的适应这些新技术所带来的一些问题. 对于流程行问题,敏捷的Scrum能够很好的提升产品开发团队之间的协作问题,那么对于应用变的越来越复杂这种情况,它最直接的问题就是带来了开发运维的复杂性,这个时候我们就需要使用工具来解

  • C语言实现字符串字符反向排列的方法详解

    目录 前言 非递归方法 1.循环实现 2.函数实现 递归方法 1.递归方法 2.递归方法 小结 前言 重点的话说在前头,注意不是逆序打印 今天写题,碰到一个很好的题,在这里来个大家做个分享,我会用多种方法来解决 题目具体内容如下: 编写一个函数(递归实现) 实现:将参数字符串中的字符反向排列,不是逆序打印. 要求:不能使用C函数库中的字符串操作函数 但是这里我不会仅仅局限于题目的要求 非递归方法 1.循环实现 1.1循环实现(sizeof) #include <stdio.h> int mai

  • JavaScript手写异步加法asyncAdd方法详解

    目录 前言 分析 asyncAdd 直观的基本要求 隐藏的考察点 — setTimeout & cb 隐藏的考察点 — async & await 实现 asyncAdd 具体实现 进行优化 抽离内层函数 缓存计算结果 前言 在掘金上发现一道既简单但个人觉得还挺有意思的一道题,题目如下: // 异步加法 function asyncAdd(a,b,cb){ setTimeout(() => { cb(null, a + b) }, Math.random() * 1000) } as

  • Go语言基础语法之结构体及方法详解

    结构体类型可以用来保存不同类型的数据,也可以通过方法的形式来声明它的行为.本文将介绍go语言中的结构体和方法,以及"继承"的实现方法. 结构体类型 结构体类型(struct)在go语言中具有重要地位,它是实现go语言面向对象编程的重要工具.go语言中没有类的概念,可以使用结构体实现类似的功能,传统的OOP(Object-Oriented Programming)思想中的继承在go中可以通过嵌入字段的方式实现. 结构体的声明与定义: // 使用关键字 type 和 struct 定义名字

  • Jquery遍历筛选数组的几种方法和遍历解析json对象,Map()方法详解以及数组中查询某值是否存在

    1.jquery grep()筛选遍历数组(可以得到反转的数组) // 1.jquery grep()筛选遍历数组(可以得到反转的数组) var array = [1,5,9,3,12,4,48,98,4,75,2,10,11]; var filterArray = $.grep(array,(currentValue) => { return currentValue > 10; }); console.log(`${filterArray}---${filterArray.length}`

  • Go语言Web编程实现Get和Post请求发送与解析的方法详解

    本文实例讲述了Go语言Web编程实现Get和Post请求发送与解析的方法.分享给大家供大家参考,具体如下: 这是一篇入门文章,通过一个简单的例子介绍Golang的Web编程主要用到的技术. 文章结构包括: 1. Client-Get 请求 2. Client-Post 请求 3. Server 处理 Get 和 Post 数据 在数据的封装中,我们部分采用了json,因而本文也涉及到Golang中json的编码和解码. 一.Client-Get 复制代码 代码如下: package main i

随机推荐