如何让char不要忽略开头的空格_如何使用C语言实现JSON解析库(二)

上篇已实现构建节点树函数接口,该篇介绍如何将代码构建的节点树按格式化打印出来。

  • 基本思路

    从根节点开始遍历,采用广度优先。

如何广度优先呢?定义一对字符串数组,分别存放名称和数值,这对数组构成键值对。

     继续拿上篇例子举例:

输入root节点->判断为cJSON_Object类型->判断有3个子节点->遍历节点。

首先依次遍历 Gear(name)->Music(name)->Call(name) ,依次将节点名称放入数组

 name0[] ={"\"Gear\"", "\"Music\"", "\"Call\""}

然后再依次遍历Gear(value)->Music(value)->Call(value),依次将节点value放入数组

 value0[] = { "[\"P\",\"R\",\"N\",\"D\",\"S\"]", 

                   "{\n\t\t\"song\": \"This is a song title\",\n\t\t\"isPlaying\": false\n\t},", 

                    "{\n\t\t\"name\": null,\n\t\t\"number\": \"13566136676\",\n\t\t\"duration\":  180\n\t}" }

然后将name0与value0进行拼接,最后输出。

其过程中当遍历到Music(value)

name1[] = {"\"song\"", "\isPlaying\""}

value1[] = {"\"This is a song title\"", "false"}

将name1和value1进行拼接得到value0[1]

当遍历到Call(value)

name2[] = {"\"name\"", "\number\"", "\"duration\""}

value2[] = {"null, \"13566136676\"", "180"}

将name2与value2拼接得到value0[2]

先看运行结果:

23b56b04ddea08733e0c0c208eb72214.png

cJSON.h头文件:

//调用该函数,从根节点开始打印char *cJSON_Print(cJSON *root);//判断节点类型char *print_value(cJSON *item, int depth);/*根据节点类型格式化输出对应的值*/char *print_array(cJSON *item, int depth);char *print_object(cJSON *item, int depth);char *print_string( cJSON *item );char *print_number(cJSON *item);const char *cJSON_strdup(const char *str);//格式化输出字符串,例如将"Gear"输出为"\"Gear\""char *cJSON_formatString(const char *string);

cJSON.c源文件:

char *cJSON_Print(cJSON *root){  return print_value(root, 0);}char *print_value(cJSON *item, int depth){  if (!item) { return NULL; }  char *out = NULL;/*有些编译器中会把define理解为int以外的类型来处理,为保证输出为int,统一用按位与的方式(不会影响值)做转换确保最后输出类型都是int*/  switch (item->type & 255) {    case cJSON_NULL: out = cJSON_strdup("null"); break;    case cJSON_False: out = cJSON_strdup("false"); break;    case cJSON_True: out = cJSON_strdup("true"); break;    case cJSON_Number: out = print_number(item); break;    case cJSON_String: out = print_string(item); break;    case cJSON_Array: out = print_array(item, depth); break;    case cJSON_Object: out = print_object(item, depth); break;  }  return out;}char *print_array(cJSON *item, int depth){  if (!item) { return NULL; }  char **names = NULL, **entries = NULL;//name/value键值对  char *out = NULL, *ptr;  int len = 0;  //计算子节点个数  int numEntries = 0;  cJSON *child = item->child;  while (child)  {    numEntries++;    child = child->next;  }  //若子节点个数为0  if (!numEntries)  {    out = cJSON_malloc( 3 );    if(!out){return NULL;}    strcpy(out, "[]");    return out;  }  //子节点个数不为0  entries = (char**)cJSON_malloc(numEntries * sizeof(char*));  if (!entries) { return NULL; }  names = (char**)cJSON_malloc(numEntries * sizeof(char*));  if (!names) { cJSON_free(entries); return NULL; }  memset(entries, 0, numEntries * sizeof(char*));  memset(names, 0, numEntries * sizeof(char*));  child = item->child;  ++depth;  for (int i = 0; i < numEntries; i++)  {    len += depth;//加depth个\t    names[i] = cJSON_formatString(child->nameString);    len += strlen(names[i]) + 2;//加一个冒号,加一个空格    entries[i] = print_value(child, depth);    len += strlen(entries[i]);    if (i != numEntries - 1) { len++; }//加个逗号    //len++;//加个换行    child = child->next;  }  //字符串拼接  len += depth - 1;//给]加depth-1个\t  out = cJSON_malloc(len + 3);//[]\0  if(!out){return NULL;}  ptr = out;  *ptr++ = '[';//  *ptr++ = '\n';  for (int i = 0; i < numEntries; i++)  {  //  for (int j = 0; j < depth; j++) { *ptr++ = '\t'; }        if (strcmp(names[i], "\"\""))    {      strcpy(ptr, names[i]);      ptr += strlen(names[i]);      *ptr++ = ':';      *ptr++ = '\x20';    }    strcpy(ptr, entries[i]);    ptr += strlen(entries[i]);    if (i != numEntries - 1) { *ptr++ = ','; }  //  *ptr++ = '\n';  }  //for (int j = 0; j < depth - 1; j++) { *ptr++ = '\t'; }  *ptr++ = ']';  *ptr++ = '\0';  cJSON_free(names);  cJSON_free(entries);  return out;}char *print_object(cJSON *item, int depth){  if (!item) { return NULL; }  char **names = NULL, **entries = NULL;  char *out = NULL, *ptr;  int len = 0;  //计算子节点个数  int numEntries = 0;  cJSON *child = item->child;  while (child)  {    numEntries++;    child = child->next;  }  //若子节点个数为0  if (!numEntries)  {    out = cJSON_malloc(4 + depth);    if(!out){return NULL;}    ptr = out;    *ptr++ = '{';    *ptr++ = '\n';    for (int i = 0; i < depth; i++) { *ptr++ = '\t'; }    *ptr++ = '}';    *ptr++ = '\0';    return out;  }  //子节点个数不为0  entries = (char**)cJSON_malloc(numEntries * sizeof(char*) );  if (!entries) { return NULL; }  names = (char**)cJSON_malloc(numEntries * sizeof(char*) );  if (!names) { cJSON_free(entries); return NULL; }  memset(entries, 0, numEntries * sizeof(char*) );  memset(names, 0, numEntries * sizeof(char*) );    child = item->child;  ++depth;  for (int i = 0; i < numEntries; i++)  {    len += depth;//加depth个\t    names[i] = cJSON_formatString( child->nameString );    len += strlen(names[i])+2;//加一个冒号,加一个空格     entries[i] = print_value(child, depth);    len += strlen(entries[i]);    if (i != numEntries - 1) { len++; }//加个逗号    len++;//加个换行    child = child->next;  }  //字符串拼接  len += depth - 1;//给}加depth-1个\t  out = cJSON_malloc( len + 4  );//{\n}\0  if(!out){return NULL;}  ptr = out;  *ptr++ = '{';  *ptr++ = '\n';  for (int i = 0; i < numEntries; i++)  {    for (int j = 0; j < depth; j++) { *ptr++ = '\t'; }    strcpy(ptr, names[i]);    ptr += strlen(names[i]);    *ptr++ = ':';    *ptr++ = '\x20';    strcpy(ptr, entries[i]);    ptr += strlen(entries[i]);    if (i != numEntries-1) { *ptr++ = ','; }    *ptr++ = '\n';      }  for (int j = 0; j < depth - 1; j++) { *ptr++ = '\t'; }  *ptr++ = '}';  *ptr++ = '\0';  cJSON_free(names);  cJSON_free(entries);  return out;}char *print_string(cJSON *item){  if (!item) { return NULL; }  return cJSON_formatString(item->valueString);}char *cJSON_formatString(const char *string){  char *out = NULL, *ptr;  int flag = 0, len = 0;  //若空指针,则输出\"\"  if (!string)  {    out = (char*)cJSON_malloc(3);//\"\"\0    if (!out) { return NULL; }    strcpy(out, "\"\"");    return out;   }    //遍历是否为特殊字符  for (ptr = string; *ptr ; ptr++)  {    flag |= ((*ptr>0 && *ptr<32) || (*ptr == '\"') || (*ptr == '\\')) ? 1 : 0;  }    //非特殊字符  if (!flag)  {    ptr = string;    len = strlen(string);    out = (char*)cJSON_malloc(len + 3);//"xxx"\0    if (!out) { return NULL; }    ptr = out;    *ptr++ = '\"';    strcpy(ptr, string);    ptr += len;    *ptr++ = '\"';    *ptr++ = '\0';    return out;  }  //存在特殊字符  ptr = string;  unsigned char token;  //计算字符串需要的长度  while ((token = *ptr) && ++len)  {    /*\b退格  \f换页  \n换行 \r回车 \t水平制表符tab*/    if (strchr("\"\\\b\f\n\r\t", token))    {       //要输出特殊字符要做特殊处理,否则特殊字符会被计算机识别成一个字符      //例如"\""要转成"\\\""; "要输出"\n"得转成"\\n"; "\\"要转成"\\\\";"\b"转成"\\b";故字符长度要加1      len++;    }    else if (token < 32)     {    //把所有 ASCII 可显示字符以外的统统转义为 Unicode,    //例如\a转成\u0007,故字符长度要加5    //这样处理的目的是避免调用不同编码的文件时出现乱码      len += 5;      }    ptr++;  }  out = (char *)cJSON_malloc(len + 3);  if (!out) return NULL;    char *ptr2;  ptr2 = out;  ptr = string;  *ptr2++ = '\"';  while (*ptr)  {//非特殊字符    if ((unsigned char)*ptr > 31 && *ptr != '\"' && *ptr != '\\')    {      *ptr2++ = *ptr++;    }    else//特殊字符    {      *ptr2++ = '\\';      switch (token = *ptr++)      {        case '\\': *ptr2++ = '\\'; break;        case '\"': *ptr2++ = '\"'; break;        case '\b': *ptr2++ = '\b'; break;        case '\f': *ptr2++ = '\f'; break;        case '\n': *ptr2++ = '\n'; break;        case '\r': *ptr2++ = '\r'; break;        case '\t': *ptr2++ = '\t'; break;      default:        //非法字符,直接输出字符的Unicode        sprintf(ptr2, "u%04x", token);        ptr2 += 5;        break;      }    }  }  *ptr2++ = '\"';  *ptr2++ = '\0';//让指针ptr2指向其它区域,防止再次修改到该字符  return out;}char *print_number(cJSON *item){  if (!item) { return NULL; }  char *out = NULL, *str;  double d = item->valueDouble;  if (d == 0)//item中无数据存放  {    str = (char *)cJSON_malloc(2);    out = str;    if (str) strcpy(str, '0');  }  /*  1.DBL_EPSILON最小有效数字,数学极限思维极小值    若fabs((item->valueDouble) - (int)(item->valueInt)) <= DBL_EPSILON成立,则判断valueDouble与valueInt相等  2.判断是否溢出  因为int占4字节32位,根据二进制编码的规则,INT_MAX = 2^31-1,INT_MIN= -2^31.C/C++中,所有超过该限值的数,都会出现溢出,出现warning,但是并不会出现error。  如果想表示的整数超过了该限值,可以使用长整型long long 占8字节64位  */  else if (fabs((double)(item->valueInt) - d) <= DBL_EPSILON && d <= INT_MAX && d >= INT_MIN)  {    // 2^64+1=21个字符,其中一个\0    str = cJSON_malloc(21);    out = str;    if (str) { sprintf(str, "%d", item->valueInt); }  }  else  {    str = (char *)cJSON_malloc(64);    out = str;    if (str)    {      //如果小数值非常接近零,且整数部分值特别大,那么就以xxxxx.0方式输出      if (((floor(d) - d) <= DBL_EPSILON) && fabs(d) < 1.0e60) { sprintf(str, "%.0f", d); }      //若数值比1.0e-6小或比1.0e9大,则较适合用科学计数法表示      else if (fabs(d)<1.0e-6 || fabs(1.0e9)) { sprintf(str, "%e", d); }      //小数形式输出,默认保留6位小数      else { sprintf(str, "%f", d); }    }  }  return out;}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值