从最早使用的C-JSON,性能没什么问题,缺点是最大只支持32层嵌套,不过可以通过修改宏来增加嵌套层数, 最近使用LUA开发服务器业务部分,找了几个JSON库,要么标准支持不尽人意,要么则是使用LUA实现的,性能无法满足要求。与其漫无目的在网络上到处寻找,不如自己动手写一个。反正这东西也不复杂。定了个简单的设计要求:

  • 使用C语言开发,编译为LUA模块.
  • 支持UTF-8 JSON 中一般是 \uxxxx这类编码.
  • 无限级对象数组嵌套.
  • 支持object array string number 类型.
  • 提供2个最简单的接口 json_encode json_decode

下面是代码

lua-json.h

#ifndef _LUA_JSON_PARSER_H
#define _LUA_JSON_PARSER_H
/*
License: MIT
Author: bywayboy<bywayboy@gmail.com>
Date: 2014-11-21
*/int lua_json_decode(lua_State * L);
int lua_json_encode(lua_State * L);
#endif

lua-json.c

/*
License: MIT
Author: bywayboy<bywayboy@gmail.com>
Date: 2014-11-21
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>#include "lua.h"
#include "lauxlib.h"
#include "lua-json.h"#include "automem.h"enum{json_error_ok = 0,json_error_bad_value,json_error_bad_separator,json_error_bad_character,json_error_bad_string,json_error_array_noclose,json_error_object_noclose,
};
enum{lt_string,lt_string_escape,lt_string_escape_unicode,lt_array_normal,lt_array_sep,lt_object_normal,lt_object_sep,  //  :lt_object_sep2, //  ,lt_object_value,
};#define     ch_is_space( x) (x == ' ') || (x == '\t') || (x == '\r') || (x == '\n')
#define     ch_is_hex( x )  \
(('0'<=(x) && '9'>=(x)) || ('a'<=(x) && 'f'>=(x)) || ('A'<=(x) && 'F'>=(x)))typedef struct jsontok jsontok_t;
typedef struct jsonenc jsonenc_t;
struct jsontok{lua_State * L;char * jstr;int pos,size;int row;// lineint col; // charatorint err;automem_t mem;numberx
};
struct jsonenc{lua_State * L;automem_t mem;int unescape_utf;
};
#define JSONTOK_NEWLINE( tok ) (tok)->row++; (tok)->col=(tok)->posstatic int _lua_json_parse_value(jsontok_t * tok);static int _lua_json_parser_key(jsontok_t *tok){int i=0;char c;while(tok->pos < tok->size){c = tok->jstr[tok->pos+i];//如果是合法的,继续下一个if(('a'<=c && 'z'>=c) || ('A'<=c && 'Z'>=c) ) goto parser_key_continue; //-- 属性名称可以是字母if(i==0 && '_'==c) goto parser_key_continue;            //-- 属性名称可以是下划线开头.if(i >0 && ('0'<=c && '9'>=c))goto parser_key_continue; //-- 属性名称中间是可以允许出现数字的.// key 还是有数据的.if(i >0){lua_pushlstring(tok->L, &tok->jstr[tok->pos],i);tok->pos+=i;return 0;}break;
parser_key_continue:i++;tok->pos;continue;}tok->err = json_error_bad_character;tok->pos = i;return -1;
}
static int _lua_json_parse_string(jsontok_t * tok, const char quote)
{char c;int ps =tok->pos,s =lt_string;if(0 == quote)return _lua_json_parser_key(tok);while(tok->pos < tok->size){c = tok->jstr[tok->pos];switch(s){case lt_string:switch(c){case '\n': tok->pos++; JSONTOK_NEWLINE(tok); break; // new line.case '\\': tok->pos++; s=lt_string_escape;break;    // switch to escape string.case '\'':case '"':if(c != quote){tok->pos++;automem_append_byte(&tok->mem,c);break;}//TODO: finish the string.lua_pushlstring(tok->L, (char *)tok->mem.pdata,tok->mem.size);tok->mem.size=0;tok->pos++;return 0;default:tok->pos++;automem_append_byte(&tok->mem, c);break;}break;case lt_string_escape:switch(c){case 'b': automem_append_byte(&tok->mem, '\b');tok->pos++;s=lt_string;break;case 'n': automem_append_byte(&tok->mem, '\n');tok->pos++;s=lt_string;break;case 'r': automem_append_byte(&tok->mem, '\r');tok->pos++;s=lt_string;break;case 't': automem_append_byte(&tok->mem, '\t');tok->pos++;s=lt_string;break;case 'f': automem_append_byte(&tok->mem, '\f');tok->pos++;s=lt_string;break;case '\\': automem_append_byte(&tok->mem, '\\');tok->pos++;s=lt_string;break;case '/': automem_append_byte(&tok->mem, '/');tok->pos++;s=lt_string;break;case 'u':s=lt_string_escape_unicode;tok->pos++;break;default:automem_append_byte(&tok->mem,'\\');automem_append_byte(&tok->mem,c);tok->pos++;s=lt_string;break;}break;case lt_string_escape_unicode:{   //--处理 4个字节的UNICODEchar * pt=&tok->jstr[tok->pos];if(ch_is_hex(pt[0]) && ch_is_hex(pt[1]) && ch_is_hex(pt[2]) && ch_is_hex(pt[3])){//是正确的 UNICODE.unsigned short uni = (hex2byte((unsigned char *)&pt[0]) << 8) | hex2byte((unsigned char *)&pt[2]);if(0x80 > uni){ //1 bytesautomem_append_byte(&tok->mem, uni & 0x7F);}else if(0x800 > uni){ //2 bytesautomem_append_byte(&tok->mem, (0xC0 | ((uni >> 6) & 0x3F)));automem_append_byte(&tok->mem, 0x80 | (0x3F & uni));}else if(0x10000 > uni){ //3 bytesautomem_append_byte(&tok->mem, (0xE0 | ((uni >> 12))));automem_append_byte(&tok->mem, (0xC0 | ((uni >> 6) & 0x3F)));automem_append_byte(&tok->mem, 0x80 | (0x3F & uni));}else if(0x110000 > uni){ // 4 bytes.automem_append_byte(&tok->mem, (0xF0 | ((uni >> 18) & 0x07)));automem_append_byte(&tok->mem, (0xE0 | ((uni >> 12) & 0x3F)));automem_append_byte(&tok->mem, (0xC0 | ((uni >> 6) & 0x3F)));automem_append_byte(&tok->mem, 0x80 | (0x3F & uni));}tok->pos+=4;s=lt_string;break;}}tok->pos++;s=lt_string;automem_append_voidp(&tok->mem,"\\u",2);automem_append_byte(&tok->mem,c);break;}}tok->err=json_error_bad_string;return -1;
}static int _lua_json_parse_array(jsontok_t * tok){char c,s=lt_array_normal;int i=0,r,idx=1;lua_checkstack(tok->L, 5);lua_newtable(tok->L);while(tok->pos < tok->size){c= tok->jstr[tok->pos];switch(s){case lt_array_normal:switch(c){case '\n': tok->pos++; JSONTOK_NEWLINE(tok); break; // new line.case '\r':case '\t':case ' ': tok->pos++; break;    // skip space charactercase ',':                                           //  double ,tok->err = json_error_bad_separator;return -1;case '[':tok->pos++;if(0 > (r = _lua_json_parse_array(tok)))return r;s=lt_array_sep;lua_rawseti(tok->L,-2,idx++);break;case ']':return 0;default:if(0 > (r=_lua_json_parse_value(tok))){lua_pop(tok->L,1);return r;}s=lt_array_sep;lua_rawseti(tok->L,-2,idx++);break;}break;case lt_array_sep:switch(c){case '\n': tok->pos++; JSONTOK_NEWLINE(tok);break;  // new line.case '\r':case '\t':case ' ': tok->pos++;break;     // skip space charactercase ',': tok->pos++; s=lt_array_normal; break;     //  has to next array elm.case ']': tok->pos++; return 0; // array parse filish.default: //!!! got error .tok->err = json_error_bad_character;return -1;}break;}}tok->err = json_error_array_noclose;return -1;
}static int _lua_json_parser_object(jsontok_t * tok){char c,s = lt_object_normal;int r;lua_checkstack(tok->L, 5);lua_newtable(tok->L);while(tok->pos < tok->size){c=tok->jstr[tok->pos];switch(s){case lt_object_normal: //解析属性名称的部分.switch(c){case '\n': tok->pos++;JSONTOK_NEWLINE(tok);break;case '\r':case '\t':case ' ':tok->pos++;break;case '"':case '\'':tok->pos++;if(0 > (r= _lua_json_parse_string(tok, c)))return r;s=lt_object_sep;break;case '}':tok->pos++;return 0;default:if('_'==c || ('a'<=c && 'z'>=c) || ('A'<=c && 'Z'>=c)){   if(0 > (r= _lua_json_parse_string(tok, '\0')))return r;s=lt_object_sep;break;}tok->err = json_error_bad_character;return -1;}break;case lt_object_sep:switch(c){case '\n': tok->pos++;JSONTOK_NEWLINE(tok);break;case '\r':case '\t':case ' ':tok->pos++;break;case ':':tok->pos++;s=lt_object_value;break;default:tok->err = json_error_bad_character;return -1;}break;case lt_object_value:if(0 > (r= _lua_json_parse_value(tok)))return r;lua_settable(tok->L, -3);s=lt_object_sep2;break;case lt_object_sep2:switch(c){case '\n': tok->pos++; JSONTOK_NEWLINE(tok);break;  // new line.case '\r':case '\t':case ' ': tok->pos++;break;     // skip space charactercase ',': tok->pos++; s=lt_object_normal; break;        //  has to next array elm.case '}': tok->pos++; return 0; // array parse filish.default: //!!! got error .tok->err = json_error_bad_character;return -1;}break;}}tok->err =json_error_object_noclose;return -1;
}
static int _lua_json_parser_number(jsontok_t * tok){char c;int i=tok->pos ,isnum;lua_Number num;do{c = tok->jstr[i++];if(('+'==c || '-' == c) || (c >='0' && c <='9') || (c >='a' && c <='f') || (c >='A' && c <='F') || ('.'==c || 'e'==c || 'E'==c || 'x'==c || 'X'==c)){continue;}break;}while(1);lua_pushlstring(tok->L, &tok->jstr[tok->pos], i-tok->pos-1);num = lua_tonumberx(tok->L, -1, &isnum);if(isnum == 0){tok->err = json_error_bad_value;return -1;};lua_pushnumber(tok->L, num);lua_replace(tok->L, -2);tok->pos +=(i-tok->pos-1);return 0;
}
// 解析器入口.
static int _lua_json_parse_value(jsontok_t * tok)
{size_t i =0,r;char c;while(tok->pos < tok->size){c = tok->jstr[tok->pos];switch(c){case '\'':case '"':tok->pos++;return _lua_json_parse_string(tok, c);//puts(tok->jstr[tok->pos]);break;case '\n':tok->pos++;JSONTOK_NEWLINE(tok);break;case '\r':case '\t':case ' ': // space character.tok->pos++;break;case '[':tok->pos++;return r =  _lua_json_parse_array(tok);break;case '{':tok->pos++;return _lua_json_parser_object(tok);case 't':case 'T':lua_pushboolean(tok->L,1);tok->pos +=4;return 0;//maby is true.break;case 'f':case 'F':lua_pushboolean(tok->L,0);tok->pos +=5;return 0;// maby is false.break;case 'n':case 'N'://maby is null.lua_pushnil(tok->L);tok->pos +=4;return 0;case '+':case '-':case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':return _lua_json_parser_number(tok);default:tok->pos++;break;}}tok->err=json_error_bad_character;return -1;
}
static const char * json_errstr(int v){char * errstr = "unknown error";switch(v){case json_error_bad_value:errstr="bad value";break;case json_error_bad_separator:errstr="bad separator";break;case json_error_bad_character:errstr="bad character";break;case json_error_bad_string:errstr="bad string";break;case json_error_array_noclose:errstr="array no close ']'";break;case json_error_object_noclose:errstr="object no close '}'";break;}return errstr;
}
int lua_json_decode(lua_State * L)
{size_t lstr;int r,top;const char * str = lua_tolstring(L, 1, &lstr);if(NULL != str && lstr > 0){jsontok_t tok;tok.pos = tok.row=tok.col =0;tok.jstr = (char *)str;tok.size = lstr;tok.err = 0;tok.L = L;top = lua_gettop(L);automem_init(&tok.mem,128);if(0 >(r = _lua_json_parse_value(&tok))){lua_settop(L, top);lua_pushboolean(L, 0);lua_pushfstring(L,"json error: %s at line:%d col:%d", json_errstr(tok.err), tok.row,tok.pos-tok.col);goto json_parser_final;}lua_pushboolean(L,1);lua_insert(L,-2);
json_parser_final:automem_uninit(&tok.mem);return 2;}return 2;
}static int json_encode_string(jsonenc_t * enc, char * vstr, int vlen){int i=0;unsigned char c,*utf8;unsigned short ucs2;automem_append_byte(&enc->mem,'"');while(i < vlen){c=vstr[i];switch(c){case '"':i++;automem_append_voidp(&enc->mem,"\\\"",2);break;case '\'':i++;automem_append_voidp(&enc->mem,"\\\'",2);break;case '\n':i++;automem_append_voidp(&enc->mem,"\\\n",2);break;case '\t':i++;automem_append_voidp(&enc->mem,"\\\t",2);break;case '\r':i++;automem_append_voidp(&enc->mem,"\\\r",2);break;case '\b':i++;automem_append_voidp(&enc->mem,"\\\b",2);break;case '\f':i++;automem_append_voidp(&enc->mem,"\\\f",2);break;default:if(enc->unescape_utf){i++;automem_append_byte(&enc->mem,c);break;}if(c < 0x80){i++;automem_append_byte(&enc->mem,c);}else if( 0xC0== (c & 0xE0)){ // 2 bytes.utf8 = (unsigned char *)&vstr[i];ucs2 = (*utf8 & 0x3F)<<6 | (*(utf8+1) & 0x3F);automem_append_voidp(&enc->mem,"\\u",2);automem_append_voidp(&enc->mem, byte2hex((ucs2 >> 8) & 0xFF),2);automem_append_voidp(&enc->mem, byte2hex(ucs2 & 0xFF),2);i+=2;}else if(0xE0 == (c & 0xF0)){// 3 bytes.utf8 = (unsigned char *)&vstr[i];ucs2 = (*utf8 & 0x1F)<<12 | (*(utf8+1) & 0x3F)<<6 | (*(utf8+2) & 0x3F);automem_append_voidp(&enc->mem,"\\u",2);automem_append_voidp(&enc->mem, byte2hex((ucs2 >> 8) & 0xFF),2);automem_append_voidp(&enc->mem, byte2hex(ucs2 & 0xFF),2);i+=3;}else if(0xF0 == (c & 0xF8)){// 4 bytes. !!!ucs2 out of range i++;automem_append_byte(&enc->mem,c);               }break;}}automem_append_byte(&enc->mem,'"');return enc->mem.size;
}static int json_encode_value(jsonenc_t * enc){int i=0,t=lua_type(enc->L, -1);size_t lkey;char s_close=']', * key;lua_checkstack(enc->L, 5);switch(t){case LUA_TTABLE:lua_pushnil(enc->L);while(lua_next(enc->L, -2)){if(i == 0){if(LUA_TSTRING == lua_type(enc->L, -2)){automem_append_byte(&enc->mem, '{');s_close = '}';key = (char *)luaL_tolstring(enc->L, -2, &lkey);json_encode_string(enc, key,lkey);lua_pop(enc->L, 1);  //-- lua checklstring change stackautomem_append_byte(&enc->mem, ':');json_encode_value(enc);}else{automem_append_byte(&enc->mem, '[');json_encode_value(enc);}i++;}else{automem_append_byte(&enc->mem, ',');if(s_close == '}'){key = (char *)luaL_tolstring(enc->L, -2, &lkey);json_encode_string(enc, key,lkey);lua_pop(enc->L, 1);  //-- lua checklstring change stackautomem_append_byte(&enc->mem, ':');json_encode_value(enc);}else{json_encode_value(enc);}}lua_pop(enc->L,1);// -- popup the value}if(0==i)automem_append_byte(&enc->mem, '[');automem_append_byte(&enc->mem, s_close);break;case LUA_TSTRING:key = (char *)luaL_tolstring(enc->L, -1, &lkey);json_encode_string(enc, key,lkey);lua_pop(enc->L,1);   //-- lua checklstring change stackbreak;case LUA_TNUMBER:key = (char *)luaL_tolstring(enc->L, -1, &lkey);automem_append_voidp(&enc->mem, key, lkey);lua_pop(enc->L,1);   //-- lua checklstring change stackbreak;case LUA_TBOOLEAN:if(lua_toboolean(enc->L,-1))automem_append_voidp(&enc->mem, "true",4);elseautomem_append_voidp(&enc->mem, "false",5);break;default:automem_append_voidp(&enc->mem, "null",4);break;}return 0;
}int lua_json_encode(lua_State * L)
{jsonenc_t enc;char * str;size_t lstr;int v,t=lua_type(L, 1);enc.L=L;enc.unescape_utf = 0;printf("arguments = %d\n",lua_gettop(L));if(lua_gettop(L) > 1)enc.unescape_utf = lua_toboolean(L, 2);switch(t){case LUA_TTABLE:enc.L = L;automem_init(&enc.mem,128);lua_pushvalue(L,1); // -- argument 1 to stack top.json_encode_value(&enc);lua_pushlstring(L,(char *)enc.mem.pdata, enc.mem.size);automem_uninit(&enc.mem);break;case LUA_TSTRING:automem_init(&enc.mem,128);str = (char *)lua_tolstring(L,1,&lstr);json_encode_string(&enc,str,lstr);lua_pushlstring(L,(char *)enc.mem.pdata, enc.mem.size);automem_uninit(&enc.mem);break;case LUA_TNUMBER:str = (char *)luaL_tolstring(L, 1, &lstr);lua_pushlstring(L, str, lstr);break;case LUA_TBOOLEAN:v = lua_toboolean(L,1);lua_pushstring(L, v?"true":"false");break;case LUA_TNIL:case LUA_TNONE:lua_pushstring(L,"null");break;default:lua_pushstring(L,"null"); //-- 其它未知类型break;}return 1;
}

DIY 一个 JSON解析器。相关推荐

  1. 手把手教你实现一个 JSON 解析器!

    1. 背景 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.相对于另一种数据交换格式 XML,JSON 有着诸多优点.比如易读性更好,占用空间更少等. 在 ...

  2. json解析对应的value为null_徒手撸一个JSON解析器

      Java大联盟 致力于最高效的Java学习 关注 作者 | 田小波 cnblogs.com/nullllun/p/8358146.html1.背景JSON(JavaScript Object No ...

  3. 模板引擎:二、实现一个Json解析器

    2.Js实现Json解析器 前言 本文主要对Json解析器的实现进行探讨. 如果想深入了解其原理,可以参考上一篇文章:模板引擎:一.理解Json解析器工作原理 项目github地址:https://g ...

  4. erlang xml 解析_用yecc(erlang)写一个json解析器

    昨天写了个json的解析器.其实yecc早看过了,只是那时对自己要求太高,想一下子写个小语言.然后大脑就陷入混乱... 后来注意力转移了.就不那么急着去开发些难道大的.今天回来一看,觉得都理解了,实践 ...

  5. 自己动手实现一个简单的JSON解析器

    1. 背景 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.相对于另一种数据交换格式 XML,JSON 有着诸多优点.比如易读性更好,占用空间更少等.在 ...

  6. json string 格式_自己动手实现一个简单的JSON解析器

    作者:田小波 原文:http://cnblogs.com/nullllun/p/8358146.html 1. 背景 JSON(JavaScript Object Notation) 是一种轻量级的数 ...

  7. 手写了一个简单的JSON解析器,网友直乎:牛!

    作者 | 田小波 来源 | http://r3m2u.cn/4455O 背景 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.相对于另一种数据交换格式 X ...

  8. string 转 json_手写Json解析器学习心得

    哦?从"{"开始,看来是个对象了! 一. 介绍 一周前,老同学阿立给我转了一篇知乎回答,答主说检验一门语言是否掌握的标准是实现一个Json解析器,网易游戏过去的Python入门培训 ...

  9. 一个简单的json解析器

    实现一个简单地json解析器. 两部分组成,词法分析.语法分析 词法分析 package com.mahuan.json;import java.util.LinkedList; import jav ...

最新文章

  1. 什么是LambdaExpression,如何转换成Func或Action(2)
  2. C++ 执行cmd命令 并获取输出
  3. rocketMq 顺序消费
  4. Java入门到大神你需要掌握这些技术
  5. AI工程师的薪资高得逆天: 2020年,是入坑的最好时机!
  6. 用swift写的一款小游戏,模仿的僵尸危机
  7. 实验五:大数据可视化工具-NodeXL
  8. pandas时间序列——时间基础、时间增量、时间周期、日期偏移处理
  9. Base64编码的图片在网页中的显示问题的解决
  10. Linux Mint 21编译Android kernel,遇到 multiple definition of `yylloc‘ 的错误解决
  11. 1.4、云计算HCIA虚拟化存储基础知识
  12. 什么蓝牙耳机颜值高?盘点四款高颜值蓝牙耳机
  13. 安卓上利用百度输入法提供的导入词库与个性短语,批量造词方便输入
  14. php 基于soap什么协议,网络协议 20 - RPC 协议(上)- 基于XML的SOAP协议
  15. 【图像检测】手指指尖的图像采集与检测附matlab代码
  16. java计算机毕业设计医疗器械销售电子商城源程序+mysql+系统+lw文档+远程调试
  17. 火车票能不能选座_买火车票可以选座位吗
  18. python中scale的用法_在netCDF4和Python中使用scale_factor和add_offset的示例?
  19. STM32Cube的PWM控制基础篇(一)一路PWM设置
  20. CSS3 steps逐帧动画 —— 仿人人网动画案例

热门文章

  1. mysql卸载不掉? 帮你清理注册表,重新安装数据库mysql
  2. android 外接USB扫码器应用闪退解决方法
  3. SpringBoot之DispatcherServlet详解及源码解析
  4. Kafka:分布式消息系统
  5. Python format 格式化输入字符对不齐解决
  6. python—简单数据抓取六(安装scrapy环境并创建爬虫项目、以顶点小说网为例利用scrapy进行爬取、scrapy相关的注意事项)
  7. 在scrapy中params无处安放???
  8. Halcon XLD 算子集合
  9. 一个中东外贸业务员分享的干货
  10. [深度学习从入门到女装]V-Net