用C写的json解析工具(逐步完善中)

  • Post author:
  • Post category:其他


首先是定义json结构和接口

#ifndef CJSON_CJSON_H
#define CJSON_CJSON_H

#include <basetsd.h>

typedef enum type
{
    STRING_1,
    OBJECT_1,
    BOOL_1,
    ARRAY_1,
    INTEGER_1,
    DOUBLE_1
}Type;

typedef struct cjson
{
    /*
     * 字节对齐稍后再算
     */
    struct cjson *next;
    struct cjson *prev;
    Type t;
    char *key;
    struct cjson *object; // 对象的首地址
    unsigned int object_length;
    struct cjson **array; // 数组首地址
    unsigned int array_length;
    char *string;
    long long valueInt;
    double valueDouble;
    int valueBool;
}Cjson;

/*
 *  json解析入口,使用完毕请及时释放
 */
Cjson* jsonParser(char *s);
/*
 * 创建一个新的cjson节点,并初始化
 */
static Cjson* createNewNode();
/*
 * 将数组拆分成二维数组
 */
static unsigned int getRow(char *s);
Cjson **splitArray(char *s, unsigned int *length);
/*
 *  在所有键值中寻找key,并返回key所对应的cjson
 */
Cjson *cjson_find(Cjson *root, char *key);
/*
 * 假如json 以数组为组成结构,返回第index个数组
 */
Cjson *cjson_fingArray(Cjson *root, int index);
/*
 * 计算cjson总长度,由于末尾没有逗号也会被认为有逗号,所以会比原始长度大
 */
static unsigned int cjson_all_length(Cjson *root);
/*
 * 将cjson封装字符串
 */
static void packing(Cjson *root, char **buffer, char *numberBuffer);
/*
 * 封装入口 cachelength 缓冲内存大小,如果小于零,程序会自行计算大小,使用完毕请及时释放
 */
char *cjson_toString(Cjson *root, unsigned int cacheLength);
/*
 * 删除整张或部分表,这取决于root
 */
void free_all_cjson(Cjson *root);
/*
 * 1表示删除成功,0表示失败,
 */
int free_cjsonByKey(Cjson *node, char *key);

Cjson *createRoot();

#endif //CJSON_CJSON_H

然后是辅助工具的定义

内存申请工具

#ifndef CJSON_MEMERY_APPLY_H
#define CJSON_MEMERY_APPLY_H
char* createArray(const unsigned int length);
Cjson **createJsonArrayPointer(const unsigned int length);
double* createDouble(const unsigned int length);
long long* createInteger(const unsigned int length);

#endif //CJSON_MEMERY_APPLY_H

计算数字长度

unsigned int getIntegerLength(long long l);
unsigned int getDoubleLength(double d);

json键值的分析工具

#ifndef CJSON_STRING_TOOLS_H
#define CJSON_STRING_TOOLS_H


/*
 * 判断类型,分发,返回结果
 */
void parser(char **c_ptr, Type *type, void **content);

static void parseValue(char **value, Type *t, void **content);
static void parseString(char **value, void **content);
static void parseObject(char **value, void **content);
static void parseArray(char **value, void **content);
static void parseBool(char **value, void **content);
#endif //CJSON_STRING_TOOLS_H

下面是代码。

// string_tools.c
//
//
#include "cjson.h"
#include "string_tools.h"
#include "memery_apply.h"
#include <stdlib.h>
#include <stdio.h>

/*
 * 截取字符串,判断类型,分发,返回结果
 * c_ptr:游标指针
 */
void parser(char **c_ptr, Type *t, void **content)
{
    if('"' == **c_ptr)
    {
        *t = STRING_1;
        parseString(c_ptr, content);
    }
    else if('[' == **c_ptr)
    {
        *t = ARRAY_1;
        parseArray(c_ptr, content);
    }
    else if('{' == **c_ptr)
    {
        *t = OBJECT_1;
        parseObject(c_ptr, content);
    }
    else if('t' == **c_ptr || 'f' == **c_ptr)
    {
        *t = BOOL_1;
        parseBool(c_ptr, content);
    }
    else if(**c_ptr <= '9' && **c_ptr >= '0')
    {
        parseValue(c_ptr, t, content);
    }
}

static void parseValue(char **value, Type *t, void **content)
{
    *t = INTEGER_1;
    unsigned int content_length = 0;
    char *temp = *value;
    char *temp1 = *value;
    while (*temp != ',' && *temp != ']' && *temp != '}')
    {
        content_length++;
        temp++;
    }
    temp = createArray(content_length);
    int tempCursor = 0;
    while (*temp1 != ',' && *temp1 != ']' && *temp1 != '}')
    {
        if(*temp1 == '.')
        {
            *t = DOUBLE_1;
        }
        temp[tempCursor] = *temp1;
        temp1++;
        tempCursor++;
    }
    temp[tempCursor] = '\0';
    (*value) += content_length;
    if(*t == DOUBLE_1)
    {
        double *i = createDouble(1);
        *i = strtod(temp, NULL);
        free(temp);
        *content = (void*)i;
    }
    else
    {
        long long *i = createInteger(1);
        *i = strtol(temp, NULL, 10);
        free(temp);
        *content = (void*)i;
    }
}
static void parseString(char **value, void **content)
{
    (*value)++;
    unsigned int content_length = 0;
    char *temp = *value;
    char *temp1 = *value;
    while (*temp != '"')
    {
        content_length++;
        temp++;
    }
    // 去掉双引号
    temp = createArray(content_length);
    int tempCursor = 0;
    while (*temp1 != '"')
    {
        temp[tempCursor] = *temp1;
        temp1++;
        tempCursor++;
    }
    (*value) += content_length;
    temp[tempCursor] = '\0';
    *content = (void*)temp;
    (*value)++;
}
static void parseBool(char **value, void **content)
{
    unsigned int content_length = 0;
    char *temp = *value;
    char *temp1 = *value;
    while (*temp != ',' && *temp != ']' && *temp != '}')
    {
        content_length++;
        temp++;
    }
    temp = createArray(content_length);
    int tempCursor = 0;
    while (*temp1 != ',' && *temp1 != ']' && *temp1 != '}')
    {
        temp[tempCursor] = *temp1;
        temp1++;
        tempCursor++;
    }
    (*value) += content_length;
    temp[tempCursor] = '\0';
    *content = (void*)temp;
}
static void parseObject(char **value, void **content)
{
    unsigned int content_length = 0;
    char *temp = *value;
    char *temp1 = *value;
    int bBrackets = 1;

        temp++;
        content_length++;
        while (1)
        {
            if('{' != *temp && '}' != *temp)
            {
                temp++;
                content_length++;
                continue;
            }
            if('{' == *temp)
            {
                temp++;
                content_length++;
                bBrackets++;
            }
            if('}' == *temp)
            {
                temp++;
                content_length++;
                bBrackets--;
            }
            if(0 == bBrackets)
            {
                break;
            }
        }

    temp = createArray(content_length);
    int tempCursor = 0;

        temp[tempCursor++] = *temp1;
        temp1++;
        bBrackets = 1;
        while (1)
        {
            if('{' != *temp1 && '}' != *temp1)
            {
                temp[tempCursor++] = *temp1;
                temp1++;
                continue;
            }
            if('{' == *temp1)
            {
                temp[tempCursor++] = *temp1;
                temp1++;
                bBrackets++;
            }
            if('}' == *temp1)
            {
                temp[tempCursor++] = *temp1;
                temp1++;
                bBrackets--;
            }
            if(0 == bBrackets)
            {
                break;
            }
        }

    (*value) += content_length;
    temp[tempCursor] = '\0';
    *content = (void*)temp;
}
static void parseArray(char **value, void **content)
{
    unsigned int content_length = 0;
    char *temp = *value;
    char *temp1 = *value;
    int mBrackets = 1;

        content_length++;
        temp++;
        while (1)
        {
            if('[' != *temp && ']' != *temp)
            {
                temp++;
                content_length++;
                continue;
            }
            if('[' == *temp)
            {
                temp++;
                content_length++;
                mBrackets++;
            }
            if(']' == *temp)
            {
                temp++;
                content_length++;
                mBrackets--;
            }
            if(0 == mBrackets)
            {
                break;
            }
        }

    temp = createArray(content_length);
    int tempCursor = 0;

        temp[tempCursor++] = *temp1;
        temp1++;
        mBrackets = 1;
        while (1)
        {
            if('[' != *temp1 && ']' != *temp1)
            {
                temp[tempCursor++] = *temp1;
                temp1++;
                continue;
            }
            if('[' == *temp1)
            {
                temp[tempCursor++] = *temp1;
                temp1++;
                mBrackets++;
            }
            if(']' == *temp1)
            {
                temp[tempCursor++] = *temp1;
                temp1++;
                mBrackets--;
            }
            if(0 == mBrackets)
            {
                break;
            }
        }

    (*value) += content_length;
    temp[tempCursor] = '\0';
    *content = (void*)temp;
}
//memery_apply.c

//
// 
//

#include <malloc.h>
#include <stdio.h>
#include <mem.h>
#include "cjson.h"

char* createArray(const unsigned int length)
{
    char *temp = (char*)malloc(sizeof(char) * (length+1));
    if(NULL == temp)
    {
        printf("申请内存失败,程序异常退出。\n");
        exit(-1);
    }
    memset(temp, 0, sizeof(char) * (length+1));
    return temp;
}

Cjson **createJsonArrayPointer(const unsigned int length)
{
    Cjson **temp = (Cjson**)malloc(sizeof(Cjson*) * (length));
    if(NULL == temp)
    {
        printf("申请内存失败,程序异常退出。\n");
        exit(-1);
    }
    memset(temp, 0, sizeof(Cjson*) * (length));
    return temp;
}
double* createDouble(const unsigned int length)
{
    double *temp = (double*)malloc(sizeof(double) * length);
    if(NULL == temp)
    {
        printf("申请内存失败,程序异常退出。\n");
        exit(-1);
    }
    memset(temp, 0, sizeof(int) * length);
    return temp;
}

long long* createInteger(const unsigned int length)
{
    long long *temp = (long long*)malloc(sizeof(long long) * length);
    if(NULL == temp)
    {
        printf("申请内存失败,程序异常退出。\n");
        exit(-1);
    }
    memset(temp, 0, sizeof(long long) * length);
    return temp;
}
// number_tools.c

#define EPS 1e-12
unsigned int getIntegerLength(long long l)
{
    long long temp = 10l;
    unsigned int len = 1;
    while (l/temp != 0)
    {
        temp = temp * 10l;
        len++;
    }
    return len;
}

unsigned int getDoubleLength(double d)
{
    long long high = (long long)d;
    double low = d - high;
    unsigned int len = getIntegerLength(high);
    double temp = low, a = 0.1;
    while (low > EPS)
    {
        low -= a * (long long)(temp * 10l);
        a /= 10.0;
        temp = temp * 10 - (long long)(temp*10);
        len++;
    }
    return len+1;
}
// cjson.c
//
// Created by admin on 2017/8/13.
//

#include "cjson.h"
#include "string_tools.h"
#include "memery_apply.h"
#include "number_tools.h"
#include <stdio.h>
#include <assert.h>
#include <malloc.h>
#include <string.h>

#define NUMBER_BUFFER 1024
/*
 *  应该提供检查合法性的接口,不然解析中出错返回什么?
 */
Cjson* jsonParser(char *s)
{
    // 入口处应加入判断json合法性的选择
    Cjson *root = NULL;
    Cjson *nowNode = NULL; // 当期节点
    if('[' == *s)
    {
        // 如果直接是数组,直接拆了它
        root = createNewNode();
        root->t = ARRAY_1;
        root->array = splitArray(s, &root->array_length);
        return root;
    }
    if('{' == *s)
    {
        // 如果是对象
        int key_flag = 0;
        s++;
        while('}' != *s && '\0' != *s)
        {
            Type t = STRING_1;
            void *content;
            parser(&s, &t, &content); // 返回的位置一定指向, } ] : 的某一种
            if(':' == *s)
            {
                key_flag = 1;
            }
            switch (t)
            {
                case STRING_1:
                    if(key_flag)
                    {
                        // 碰到一个key就新建一个节点,指向当前节点
                        Cjson *n = createNewNode();
                        n->key = (char*)content;
                        // 更新当前节点
                        if(NULL == nowNode)
                        {
                            nowNode = n;
                            root = nowNode; // 记录首地址
                            root->object_length++;
                        }
                        else
                        {
                            nowNode->next = n;
                            n->prev = nowNode;
                            nowNode = n;
                            root->object_length++;
                        }
                    }
                    else
                    {
                        nowNode->t = t;
                        nowNode->string = (char*)content;
                    }
                    break;
                case OBJECT_1:
                    nowNode->t = t;
                    nowNode->object = jsonParser((char*)content); //返回对象首地址
                    free(content);
                    break;
                case ARRAY_1:
                    nowNode->t = t;
                    nowNode->array = splitArray(content, &nowNode->array_length); // 返回二维数组首地址
                    free(content);
                    break;
                case BOOL_1:
                    nowNode->t = t;
                    if(strcmp(content, "true") == 0)
                    {
                        nowNode->valueBool = 1;
                    }
                    else
                    {
                        nowNode->valueBool = 0;
                    }
                    free(content);//不能漏掉任何一个堆内存
                    break;
                case INTEGER_1:
                    nowNode->t = t;
                    nowNode->valueInt = *(long long*)content;
                    free(content);
                    break;
                case DOUBLE_1:
                    nowNode->t = t;
                    nowNode->valueDouble = *(double*)content;
                    free(content);
                    break;
                default:
                    assert(-1);
                    break;
            }
            s++;
            key_flag = 0;
        }
        return root;
    }

}

static Cjson* createNewNode()
{
    Cjson *x = (Cjson*)malloc(sizeof(Cjson));
    x->t = STRING_1;
    x->object = NULL;
    x->string = NULL;
    x->next = NULL;
    x->prev = NULL;
    x->key = NULL;
    x->array = NULL;
    x->valueBool = 0;
    x->valueDouble = 0.0;
    x->valueInt = 0l;
    x->array_length = 0;
    x->object_length = 0;
    return x;
}

Cjson **splitArray(char *s, unsigned int *length)
{
    if(*s != '[')
    {
        return NULL;
    }
    unsigned int i = getRow(s);
    *length = i;
    Cjson **array = createJsonArrayPointer(i);
    Cjson **res = &array[0];
    s++;
    while (']' != *s && '\0' != *s)
    {
        void *content = NULL;
        Type t = STRING_1;
        parser(&s, &t, &content);
        *array = createNewNode();
        switch (t)
        {
            case STRING_1:
                (*array)->t = STRING_1;
                (*array)->string = (char*)content;
                break;
            case OBJECT_1:
                (*array)->t = OBJECT_1;
                (*array)->object = jsonParser((char*)content);
                free(content);
                break;
            case ARRAY_1:
                (*array)->t =ARRAY_1;
                (*array)->array = splitArray((char*)content, &(*array)->array_length);
                free(content);
                break;
            case INTEGER_1:
                (*array)->t = INTEGER_1;
                (*array)->valueInt = *(long long*)content;
                free(content);
                break;
            case DOUBLE_1:
                (*array)->t = DOUBLE_1;
                (*array)->valueDouble = *(double*)content;
                free(content);
                break;
            case BOOL_1:
                (*array)->t = BOOL_1;
                if(strcmp(content, "true") == 0)
                {
                    (*array)->valueBool = 1;
                }
                else
                {
                    (*array)->valueBool = 0;
                }
                free(content);
                break;
            default:
                assert(-1);
                break;
        }
        array++;
        s++;
    }
    return res;
}

static unsigned int getRow(char *s)
{
    if('[' != *s)
    {
        return 0;
    }
    int bBrackets=0,mBrackets=0;
    unsigned int rows = 0;
    s++;
    while ('\0' != *s)
    {
        if('{' == *s)
        {
            bBrackets++;
            s++;
            while (1)
            {
                if('{' != *s && '}' != *s)
                {
                    s++;
                    continue;
                }
                if('{' == *s)
                {
                    s++;
                    bBrackets++;
                }
                if('}' == *s)
                {
                    s++;
                    bBrackets--;
                }
                if(0 == bBrackets)
                {
                    rows++;
                    s++;  // 直接跳过匹配到的括号
                    break;
                }
            }
        }
        else if('[' == *s)
        {
            mBrackets++;
            s++;
            while (1)
            {
                if('[' != *s && ']' != *s)
                {
                    s++;
                    continue;
                }
                if('[' == *s)
                {
                    s++;
                    mBrackets++;
                }
                if(']' == *s)
                {
                    s++;
                    mBrackets--;
                }
                if(0 == mBrackets)
                {
                    rows++;
                    s++;  // 直接跳过匹配到的括号
                    break;
                }
            }
        }
        else
        {
            // 数字 字符串 布尔值情况
            rows++;
            while (',' != *s++);
        }
    }
    return rows;
}
Cjson *cjson_find(Cjson *root, char *key)
{
    Cjson *now = root;
    while (NULL != now)
    {
        if(OBJECT_1 == now->t)
        {
            Cjson *x = cjson_find(now->object, key);
            if(NULL != x)
            {
                return x;
            }
        }
        else if(ARRAY_1 == now->t)
        {
            Cjson **a = now->array;
            unsigned int len = now->array_length;
            for (int i = 0; i < len; ++i) {
                Cjson *x = cjson_find(a[i], key);
                if(NULL != x)
                {
                    return  x;
                }
            }
        }
        else
        {
            if(NULL != now->key)
            {
                if(0 == strcmp(key, now->key))
                {
                    return now;
                }
            }
        }
        now = now->next;
    }
    return NULL;
}

Cjson *cjson_fingArray(Cjson *root, int index)
{
    if(ARRAY_1 != root->t)
    {
        return NULL;
    }
    Cjson **now = root->array;
    int i = 1;
    int length = root->array_length;
    while (i <= length)
    {
        if(i == index)
        {
            return *now;
        }
        i++;
        now++;
    }
    return NULL;
}

static unsigned int cjson_array_all_length(Cjson *node)
{
    unsigned int length = 0;
    Cjson *temp;
    Cjson **array = node->array;
    unsigned int len = node->array_length;
    for (int i = 0; i < len; ++i) {
        temp = array[i];
        length += (cjson_all_length(temp) + 1);
    }
    return length;
}

static unsigned int cjson_all_length(Cjson *root)
{
    // 所求长度大于原长度
    unsigned int length = 0;
    Cjson *node = root;
    while (NULL != node)
    {
        if(OBJECT_1 == node->t)
        {
            length += (cjson_all_length(node->object) + 3);
        }
        else if(ARRAY_1 == node->t)
        {
            length += (cjson_array_all_length(node) + 3);
        }
        else
        {
            if(NULL != node->key)
            {
                length += (strlen(node->key) + 3);
            }
            switch (node->t)
            {
                case INTEGER_1:
                    length += getIntegerLength(node->valueInt)+2;
                    break;
                case DOUBLE_1:
                    length += getDoubleLength(node->valueDouble)+2;
                    break;
                case BOOL_1:
                    if(1 == node->valueBool)
                    {
                        length += 5; // true,
                    }
                    else
                    {
                        length += 6; // false,
                    }
                    break;
                case STRING_1:
                    length += (strlen(node->string) + 3);
                    break;
                default:
                    break;
            }
        }
        node = node->next;
    }
    return length;
}

static void packing(Cjson *root, char **buffer, char *numberBuffer)
{
    Cjson *node = root;
    char *cache = *buffer;
    while (NULL != node)
    {
        if(NULL != node->key)
        {
            *cache = '"';
            cache++;
            strcat(cache, node->key);
            cache += strlen(node->key);
            *cache = '"';
            cache++;
            *cache = ':';
            cache++;
        }
        switch (node->t)
        {
            case OBJECT_1:
                *cache = '{';
                cache++;
                packing(node->object, &cache, numberBuffer);
                *cache = '}';
                cache++;
                break;
            case ARRAY_1:
                *cache = '[';
                cache++;
                unsigned int l = node->array_length;
                Cjson *temp;
                for (int i = 0; i < l; ++i) {
                    temp = node->array[i];
                    packing(temp, &cache, numberBuffer);
                }
                *cache = ']';
                cache++;
                break;
            case INTEGER_1:
                ltoa(node->valueInt, numberBuffer, 10);
                strcat(cache, numberBuffer);
                cache += strlen(numberBuffer);
                break;
            case DOUBLE_1:
                gcvt(node->valueDouble, 10, numberBuffer);
                strcat(cache, numberBuffer);
                cache += strlen(numberBuffer);
                break;
            case BOOL_1:
                if(1 == node->valueBool)
                {
                    strcat(cache, "true");
                    cache += 4;
                }
                else
                {
                    strcat(cache, "false");
                    cache += 5;
                }
                break;
            case STRING_1:
                *cache = '"';
                cache++;
                strcat(cache, node->string);
                cache += strlen(node->string);
                *cache = '"';
                cache++;
                break;
        }
        node = node->next;
        *cache = ',';
        cache++;
    }
    cache--;
    *cache = '\0';
    *buffer = cache;
}
char *cjson_toString(Cjson *root, unsigned int cacheLength)
{
    if(NULL == root)
    {
        return "{}";
    }
    unsigned  int length = 0;
    if(cacheLength <= 0)
    {
        length = cjson_all_length(root) + 2;
    }
    else
    {
        length = cacheLength;
    }
    char *result = createArray(length);
    char *cache = result;
    char *numberBuffer = createArray(NUMBER_BUFFER-1);

    packing(root, &cache, numberBuffer);

    free(numberBuffer);
    return result;
}

static void free_all_cjson_array(Cjson *root)
{
    Cjson *node = root;
    Cjson *temp;
    Cjson **array = node->array;
    unsigned int len = node->array_length;
    for (int i = 0; i < len; ++i) {
        temp = array[i];
        free_all_cjson(temp);
    }
    free(array);
}

void free_all_cjson(Cjson *root)
{
    Cjson *node = root;
    Cjson *temp;
    while (1)
    {
        if(OBJECT_1 == node->t)
        {
            free_all_cjson(node->object);
        }
        if(ARRAY_1 == node->t)
        {
            free_all_cjson_array(node);
        }
        if(NULL == node->next)
        {
            free(node);
            break;
        }
        temp = node;
        node = node->next;
        free(temp);
    }
}

int free_cjsonByKey(Cjson *node, char *key)
{
    while (NULL != node)
    {
        if(NULL != node->key)
        {
            if(strcmp(key, node->key) == 1)
            {
                // 删除节点,连接前后节点
                return 1;
            }
        }
        node = node->next;
    }
    return 0;
}

json解析已完毕,封装还有欠缺。



版权声明:本文为nvnnv原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。