请自行约束两种语言数据结构语法上的不同,避开如下问题:

1、json本身不约束key是否符合一个编程语言中的变量名,所以编写用于和编程语言数据结构交互的json代码时应该注意key是否正确。

2、lua没有数组,利用哈希表实现的逻辑上的数组,在中间可以存在不连续的情况时json将无法识别。

3、lua的字符串key可以和数字key共存,这对于json来说,是不允许的。

这些代码我已经用了很久了,所以暂时不多解释了,依赖c++11以上的版本,

代码挺多,有需求可以直接复制,这么多代码的目的也就是更高性能,单纯的在C++里面跑,比谷歌的实现稍微快一点点。

好了,废话不多说,上代码

#pragma once
#include <string>
#include <functional>
#include <setjmp.h>
#include <fstream>
#include <vector> namespace aqx { #ifndef jsize_t
typedef unsigned int jsize_t;
#endif #ifndef jnumber_t
typedef double jnumber_t;
#endif static short constexpr jsvt_null{ 0 };
static short constexpr jsvt_string{ 1 };
static short constexpr jsvt_number{ 2 };
static short constexpr jsvt_boolean{ 3 };
static short constexpr jsvt_object{ 4 };
static short constexpr jsvt_group{ 5 }; namespace aqx_internal {
#ifndef __AQX_UTF8_CHAR_LEN
#define __AQX_UTF8_CHAR_LEN
static unsigned char utf8_char_len[] = {
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1
};
#endif static unsigned int json_char_state[] = {
0,0,0,0,0,0,0,0,0,32,96,0,0,96,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
32,0,640,0,0,0,0,0,0,0,0,1048576,65536,8192,131072,512,
3072,3072,3072,3072,3072,3072,3072,3072,3072,3072,16,0,0,0,0,0,
0,1024,1024,1024,1024,5120,1024,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,4,768,8,0,0,
0,17408,1024,1024,1024,21504,50176,0,0,0,0,0,278528,0,524800,0,
0,0,16896,16384,49664,279040,0,0,0,0,0,1,0,2,0,0
}; static int u16c2u8c(unsigned long u16c, unsigned char *u8c) {
if (u16c <= 0x0000007F) {
u8c[0] = u16c & 0x7F;
return 1;
}
else if (u16c >= 0x00000080 && u16c <= 0x000007FF) {
u8c[1] = (u16c & 0x3F) | 0x80;
u8c[0] = ((u16c >> 6) & 0x1F) | 0xC0;
return 2;
}
else if (u16c >= 0x00000800 && u16c <= 0x0000FFFF)
{
u8c[2] = (u16c & 0x3F) | 0x80;
u8c[1] = ((u16c >> 6) & 0x3F) | 0x80;
u8c[0] = ((u16c >> 12) & 0x0F) | 0xE0;
return 3;
}
else if (u16c >= 0x00010000 && u16c <= 0x001FFFFF)
{
u8c[3] = (u16c & 0x3F) | 0x80;
u8c[2] = ((u16c >> 6) & 0x3F) | 0x80;
u8c[1] = ((u16c >> 12) & 0x3F) | 0x80;
u8c[0] = ((u16c >> 18) & 0x07) | 0xF0;
return 4;
}
else if (u16c >= 0x00200000 && u16c <= 0x03FFFFFF)
{
u8c[4] = (u16c & 0x3F) | 0x80;
u8c[3] = ((u16c >> 6) & 0x3F) | 0x80;
u8c[2] = ((u16c >> 12) & 0x3F) | 0x80;
u8c[1] = ((u16c >> 18) & 0x3F) | 0x80;
u8c[0] = ((u16c >> 24) & 0x03) | 0xF8;
return 5;
}
else if (u16c >= 0x04000000 && u16c <= 0x7FFFFFFF)
{
u8c[5] = (u16c & 0x3F) | 0x80;
u8c[4] = ((u16c >> 6) & 0x3F) | 0x80;
u8c[3] = ((u16c >> 12) & 0x3F) | 0x80;
u8c[2] = ((u16c >> 18) & 0x3F) | 0x80;
u8c[1] = ((u16c >> 24) & 0x3F) | 0x80;
u8c[0] = ((u16c >> 30) & 0x01) | 0xFC;
return 6;
} return 0;
} namespace JSON_SYNTAX {
static constexpr auto _T_OBJECT_BEGIN{ static_cast<unsigned int>(0x01) }; // {
static constexpr auto _T_OBJECT_END{ static_cast<unsigned int>(0x02) }; // }
static constexpr auto _T_GROUP_BEGIN{ static_cast<unsigned int>(0x04) }; // [
static constexpr auto _T_GROUP_END{ static_cast<unsigned int>(0x08) }; // ]
static constexpr auto _T_VALUE{ static_cast<unsigned int>(0x10) }; // :
static constexpr auto _T_SPACE{ static_cast<unsigned int>(0x20) }; // 4个空白字符" \t\r\n"
static constexpr auto _T_ENDL{ static_cast<unsigned int>(0x40) }; // 2个换行符"\r\n"
static constexpr auto _T_TEXT{ static_cast<unsigned int>(0x80) }; // "
static constexpr auto _T_ESCAPE_BEGIN{ static_cast<unsigned int>(0x100) }; // 转义符开始 '\\'
static constexpr auto _T_ESCAPE_TYPE{ static_cast<unsigned int>(0x200) }; // 转义符类型 "nrtbfu\\"
static constexpr auto _T_HEX{ static_cast<unsigned int>(0x400) }; // \u之后UTF16的4字符HEX,"abcdefABCDEF"
static constexpr auto _T_NUMBER{ static_cast<unsigned int>(0x800) }; // 数字"0-9"
static constexpr auto _T_E{ static_cast<unsigned int>(0x1000) }; // 科学计数法 e或E
static constexpr auto _T_NEGATIVE{ static_cast<unsigned int>(0x2000) }; // 负数 -
static constexpr auto _T_BOOL{ static_cast<unsigned int>(0x4000) }; // true false
static constexpr auto _T_BOOL_BEGIN{ static_cast<unsigned int>(0x8000) }; // t f
static constexpr auto _T_NEXT{ static_cast<unsigned int>(0x10000) }; // ,
static constexpr auto _T_DECIMAL{ static_cast<unsigned int>(0x20000) }; // 小数点 .
static constexpr auto _T_NULL{ static_cast<unsigned int>(0x40000) }; // null
static constexpr auto _T_NULL_BEGIN{ static_cast<unsigned int>(0x80000) }; // n
static constexpr auto _T_POSITIVE{ static_cast<unsigned int>(0x100000) }; // +
} static constexpr auto _jnf{ static_cast<jsize_t>(-1) }; template<typename _Ty> class _json_parser; class _jts_base {
public:
_jts_base() {
text = nullptr;
} void init(const char *_Text, int _Size) {
text = _Text;
size = _Size;
instr = false;
flags = 0;
index = 0;
} jsize_t open_instr() {
instr = true;
jsize_t _Result = flags;
flags = 0;
return _Result;
} void close_instr(jsize_t _Flags) {
instr = false;
flags = _Flags;
} jsize_t set_flags(jsize_t _Flags) {
auto _Result = flags;
flags = _Flags;
return _Result;
} long subhextol(int left, int len) {
long _Result = 0;
int rlen = len;
for (int i = 0; i < len; i++) {
char c = text[--rlen];
long _Tmp;
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
_Tmp = c - '0';
break;
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
_Tmp = c - 'a' + 10;
break;
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
_Tmp = c - 'A' + 10;
break;
default:
return 0;
}
_Result += (_Tmp << (i << 2));
}
return _Result;
} protected:
const char *text;
jsize_t size;
unsigned int s;
char c;
unsigned char cl;
bool instr;
unsigned int flags;
jsize_t index;
std::string tmp;
}; class _jts_utf8 : public _jts_base
{
public:
int operator++() { c = text[index];
cl = utf8_char_len[(unsigned char)c];
if (cl != 1) {
if (flags == JSON_SYNTAX::_T_ESCAPE_TYPE || !instr)
return -1;
do {
index += cl;
c = text[index];
cl = utf8_char_len[(unsigned char)c];
} while (cl != 1);
}
s = json_char_state[c];
if (flags & s) {
index += cl;
return 0;
} if (instr) {
if (s & JSON_SYNTAX::_T_ENDL)
return -1; index += cl;
return 0;
} return -1;
} private:
friend class _json_parser<_jts_utf8>;
}; class _jts_gbk : public _jts_base
{
public:
int operator++() {
c = text[index];
cl = ((unsigned char)c & 0x80) ? 2 : 1;
if (cl != 1) {
if (flags == JSON_SYNTAX::_T_ESCAPE_TYPE || !instr)
return -1;
do {
index += cl;
c = text[index];
cl = ((unsigned char)c & 0x80) ? 2 : 1;
} while (cl != 1);
}
s = json_char_state[c];
if (flags & s) {
index += cl;
return 0;
} if (instr) {
if (s & JSON_SYNTAX::_T_ENDL)
return -1; index += cl;
return 0;
} return -1;
} private:
friend class _json_parser<_jts_gbk>;
}; class _json_tree {
public:
class node {
public:
node() {
_Size = 0;
_Bgn = _Parent = _jnf;
} node(jsize_t _Pa) {
_Size = 0;
_Parent = _Pa;
_Bgn = _jnf;
} jsize_t size() {
return _Size;
} jsize_t begin() {
return _Bgn;
} private:
friend class _json_parser<_jts_utf8>;
friend class _json_parser<_jts_gbk>;
friend class _json_tree;
jsize_t _Size, _Bgn, _End, _Parent;
}; class var {
public: var() {
Key = _jnf;
Next = _jnf;
Kty = 1;
Type = 0;
} var(short _KTy, jsize_t _Key) {
Next = _jnf;
Kty = _KTy;
Key = _Key;
Type = 0;
} var(short _KTy, jsize_t _Key, short _Type, jsize_t _Val) {
Next = _jnf;
Kty = _KTy;
Key = _Key;
Type = _Type;
Off = _Val;
} var(short _KTy, jsize_t _Key, short _Type, bool _Val) {
Next = _jnf;
Kty = _KTy;
Key = _Key;
Type = _Type;
Stat = _Val;
} var(short _KTy, jsize_t _Key, short _Type, jnumber_t _Val) {
Next = _jnf;
Kty = _KTy;
Key = _Key;
Type = _Type;
Number = _Val;
} short type() { return Type; }
bool is_ikey() { return Kty == 1; }
var *next(_json_tree &_Tree) {
if (Next == _jnf)
return nullptr;
return _Tree.get_val(Next);
} jsize_t ikey() {
return (is_ikey()) ? Key : _jnf;
} const char *skey(_json_tree &_Tree) {
return (!is_ikey()) ? _Tree.get_text(Key) : "";
} bool toboolean() {
return Stat;
} const char *tostring(_json_tree &_Tree) {
return (type() == 1) ? _Tree.get_text(Off) : "";
} jnumber_t tonumber() {
return (type() == 2) ? Number : 0;
} node *toobject(_json_tree &_Tree) {
return (type() == aqx::jsvt_object || type() == aqx::jsvt_group) ? _Tree.get_node(Off) : nullptr;
} private:
friend class _json_parser<_jts_utf8>;
friend class _json_parser<_jts_gbk>;
friend class _json_tree;
jsize_t Key;
jsize_t Next;
short Type;
short Kty;
union {
bool Stat;
jsize_t Off;
jnumber_t Number;
};
}; _json_tree() {
_Texts = { 0, 0, 0 };
} node *get_root() {
if (_Nodes.size() < 2)return nullptr;
return get_node(1);
} var *get_root_val() {
if (_Nodes.size() < 2)return nullptr;
return get_val(1);
} node *get_node(jsize_t _Ref) { return (_Ref < (jsize_t)_Nodes.size()) ? &(_Nodes[_Ref]) : nullptr; }
var *get_val(jsize_t _Ref) { return (_Ref < (jsize_t)_Vals.size()) ? &(_Vals[_Ref]) : nullptr; }
const char *get_text(jsize_t _Ref) { return (_Ref <= _Texts.size) ? _Texts.data + _Ref : nullptr; } void reserve(jsize_t _TextSize, jsize_t _Count) {
if (_TextSize << 1 > _Texts.capacity)
_Realloc_Texts(_TextSize << 1);
_Vals.reserve(_Count << 1);
_Nodes.reserve(_Count);
} void clear() {
_Texts.size = 0;
_Vals.clear();
_Nodes.clear();
} private:
void _set_child(node *e, jsize_t v) {
if (e->_Bgn == _jnf) {
e->_Bgn = v;
e->_End = v;
}
else {
get_val(e->_End)->Next = v;
e->_End = v;
}
} jsize_t new_node(jsize_t _Node, jsize_t &_Name, short _Type) {
jsize_t _Result = (jsize_t)_Nodes.size();
_Nodes.push_back(node(_Node));
jsize_t v = (jsize_t)_Vals.size();
auto e = get_node(_Node);
if (_Name != _jnf) {
_Vals.push_back(var(0, _Name, _Type, _Result));
_Name = _jnf;
e->_Size++;
}
else
_Vals.push_back(var(1, e->_Size++, _Type, _Result));
_set_child(e, v);
return _Result;
} jsize_t new_root() {
jsize_t _Result = (jsize_t)_Nodes.size();
_Nodes.push_back(node());
jsize_t v = (jsize_t)_Vals.size();
_Vals.push_back(var(1, _jnf, aqx::jsvt_object, _Result));
return _Result;
} void _Realloc_Texts(jsize_t _NewCapacity = 0) {
if (_NewCapacity != 0)
_Texts.capacity = (_NewCapacity + (_NewCapacity >> 1));
else
_Texts.capacity = (_Texts.capacity + (_Texts.capacity >> 1));
if (_Texts.capacity < 0x1000)
_Texts.capacity = 0x1000;
char *_Tmp = new char[_Texts.capacity];
if (_Texts.data) {
if (_Texts.size)
memcpy_s(_Tmp, _Texts.capacity, _Texts.data, _Texts.size);
delete _Texts.data;
}
_Texts.data = _Tmp;
} jsize_t new_text(const char *_Text, int _Len) {
jsize_t x = _Texts.size + (sizeof(size_t) - (_Texts.size % sizeof(size_t)));
if (x + _Len >= _Texts.capacity)
_Realloc_Texts(x + _Len);
char *_Target = _Texts.data + x;
_Texts.size = x + (_Len--);
memcpy_s(_Target, _Len, _Text, _Len);
_Target[_Len] = 0;
return x;
} void append_text(const char *_Text, int _Len) {
if (_Texts.size + _Len >= _Texts.capacity)
_Realloc_Texts(_Texts.size + _Len);
char *_Target = _Texts.data + _Texts.size - 1;
_Texts.size += _Len--;
_Texts.size--;
memcpy_s(_Target, _Len, _Text, _Len);
_Target[_Len] = 0;
} void append_char(char _Chr) {
if (_Texts.size + 1 >= _Texts.capacity)
_Realloc_Texts(_Texts.size + 1);
_Texts.data[_Texts.size - 1] = _Chr;
_Texts.data[_Texts.size++] = 0;
} void back_text(int _Len) {
_Texts.size -= _Len;
_Texts.data[_Texts.size] = 0;
} jsize_t new_var_string(jsize_t _Node, jsize_t &_Name, jsize_t _Text) {
jsize_t v = (jsize_t)_Vals.size();
auto e = get_node(_Node);
if (_Name != _jnf) {
_Vals.push_back(var(0, _Name, aqx::jsvt_string, _Text));
_Name = _jnf;
e->_Size++;
}
else
_Vals.push_back(var(1, e->_Size++, aqx::jsvt_string, _Text));
_set_child(e, v);
return v;
} jsize_t new_var_number(jsize_t _Node, jsize_t &_Name, jnumber_t _Number) {
jsize_t v = (jsize_t)_Vals.size();
auto e = get_node(_Node);
if (_Name != _jnf) {
_Vals.push_back(var(0, _Name, aqx::jsvt_number, _Number));
_Name = _jnf;
e->_Size++;
}
else
_Vals.push_back(var(1, e->_Size++, aqx::jsvt_number, _Number));
_set_child(e, v);
return v;
} jsize_t new_var_boolean(jsize_t _Node, jsize_t &_Name, bool _Stat) {
jsize_t v = (jsize_t)_Vals.size();
auto e = get_node(_Node);
if (_Name != _jnf) {
_Vals.push_back(var(0, _Name, aqx::jsvt_boolean, _Stat));
_Name = _jnf;
e->_Size++;
}
else
_Vals.push_back(var(1, e->_Size++, aqx::jsvt_boolean, _Stat));
_set_child(e, v);
return v;
} jsize_t new_var_null(jsize_t _Node, jsize_t &_Name) {
jsize_t v = (jsize_t)_Vals.size();
auto e = get_node(_Node);
if (_Name != _jnf) {
_Vals.push_back(var(0, _Name, aqx::jsvt_null, (jnumber_t)0));
_Name = _jnf;
e->_Size++;
}
else
_Vals.push_back(var(1, e->_Size++, aqx::jsvt_null, (jnumber_t)0));
_set_child(e, v);
return v;
} private:
friend class _json_parser<_jts_utf8>;
friend class _json_parser<_jts_gbk>;
std::vector<var> _Vals;
std::vector<node> _Nodes;
struct _TEXTS_POOL { char *data; jsize_t size; jsize_t capacity; }_Texts;
}; template<typename _Ty>
class _json_parser {
public:
_json_parser(_json_tree &_Tree) {
tree = &_Tree;
} bool load_string(const char *_Text, jsize_t _Len = _jnf, bool _MultiRoot = false) {
if ((int)_Len < 0)
_Len = (jsize_t)strlen(_Text) + 1;
jts.init(_Text, _Len);
tree->clear();
return j_root(_MultiRoot) == 0;
} bool load_file(const std::string _File, bool _MultiRoot = false) {
std::ifstream f(_File.c_str(), std::ifstream::binary);
if (!f)
return false;
f.seekg(0, f.end);
size_t fs = (size_t)f.tellg();
f.seekg(0, f.beg);
char *_Buf = new char[fs + 2];
_Buf[fs] = 0;
_Buf[fs + 1] = 0;
f.read(_Buf, fs);
f.close();
bool _Result = load_string(_Buf, (jsize_t)fs, _MultiRoot);
delete _Buf;
return _Result;
} jsize_t get_error_pos() { /*for (int i = err_pos; i < err_pos + 10; i++)
printf("%c", jts.text[i]);
printf("\n");*/
return err_pos;
} private:
void jtsnext() {
if ((jts.index >= jts.size) || (++jts) != 0) {
err_pos = jts.index;
longjmp(_Rem, -1);
}
} void j_ec(jsize_t &_Off, jsize_t &_TextOff) {
jsize_t len = jts.index - _Off;
if (_TextOff == (jsize_t)-1)
_TextOff = tree->new_text(jts.text + _Off, len);
else
tree->append_text(jts.text + _Off, len); jts.close_instr(JSON_SYNTAX::_T_ESCAPE_TYPE);
jtsnext();
if (jts.c == 'u') {
jsize_t ecpos = jts.index;
unsigned long _uc1 = 0;
int _uc1_len = 0;
char u8c[7];
for (;;) {
jts.set_flags(JSON_SYNTAX::_T_HEX);
for (int i = 0; i < 4; i++) {
jtsnext();
} unsigned long uc = (unsigned short)jts.subhextol(ecpos, jts.index - ecpos);
if (_uc1 >= 0xD800 && _uc1 < 0xDBFF && uc >= 0xDC00 && uc < 0xDFFF) {
int u8l = u16c2u8c((_uc1 - 0xD800) * 0x400 + (uc - 0xDC00) + 0x10000, (unsigned char*)u8c);
u8c[u8l] = 0;
tree->back_text(_uc1_len + 1);
tree->append_text(u8c, u8l + 1);
_uc1 = 0;
}
else {
_uc1 = uc;
_uc1_len = u16c2u8c(uc, (unsigned char*)u8c);
u8c[_uc1_len] = 0;
tree->append_text(u8c, _uc1_len + 1);
} jts.open_instr();
if (jts.c != '\\') {
_Off = jts.index;
jts.index--;
break;
} jts.close_instr(JSON_SYNTAX::_T_ESCAPE_TYPE);
jtsnext();
if (jts.c != 'u') {
_Off = jts.index - 1;
jts.index -= 2;
break;
}
}
}
else {
switch (jts.c)
{
case '\\':
tree->append_char('\\');
break;
case 'n':
tree->append_char('\n');
break;
case 'r':
tree->append_char('\r');
break;
case 't':
tree->append_char('\t');
break;
case 'b':
tree->append_char('\b');
break;
case 'f':
tree->append_char('\f');
break;
case '/':
tree->append_char('/');
break;
} _Off = jts.index;
} jts.open_instr(); //继续放飞自我
} void j_text(bool isname = false) {
jsize_t pos = jts.index;
auto f = jts.open_instr();//字符串里的东西就开始放飞自我了,允许所有,除了不能换行
jsize_t text_off = (jsize_t)-1;
jsize_t text_len = 0; for (;;)
{
jtsnext();
if (jts.c == '\\') {
j_ec(pos, text_off);
}
else if (jts.c == '"') {
break;
}
} jts.close_instr(f);
jsize_t len = jts.index - pos;
if (text_off == (jsize_t)-1)
text_off = tree->new_text(jts.text + pos, len);
else
tree->append_text(jts.text + pos, len); if (isname)
name_off = text_off;
else
tree->new_var_string(cur, name_off, text_off);
} void j_number() {
//考虑到可能会传入常量字符串到json解析,所以,在不拷贝源字符串,不能修改源字符串的情况下,只有自己实现数字转换的代码,这里统一使用浮点类型进行计算 /*
有一点没有遵循标准,标准对于数字前的多个0是不允许的,
但是它允许了-0 -0.00000000000 0e00000000000 之类的这些同样无意义的东西存在
而我没有判断这一点,因为我觉得这会带来额外的性能损失,也会使这段代码变得更为复杂,
我认为这一点,不管这些无意义的0在哪,由程序员自行控制它,
只约束头部,不管中间,尾巴的做法,除了降低性能,没有什么实际意义。
*/
unsigned int myf;
long double _Number = 0;
long double factor;
bool neg = false;
if (jts.c == '-') {
neg = true;
jts.set_flags(JSON_SYNTAX::_T_NUMBER);
jtsnext();
myf = JSON_SYNTAX::_T_NUMBER | JSON_SYNTAX::_T_E | JSON_SYNTAX::_T_DECIMAL |
JSON_SYNTAX::_T_SPACE | JSON_SYNTAX::_T_OBJECT_END | JSON_SYNTAX::_T_GROUP_END | JSON_SYNTAX::_T_NEXT;
jts.set_flags(myf);
}
else
{
myf = JSON_SYNTAX::_T_NUMBER | JSON_SYNTAX::_T_E | JSON_SYNTAX::_T_DECIMAL |
JSON_SYNTAX::_T_SPACE | JSON_SYNTAX::_T_OBJECT_END | JSON_SYNTAX::_T_GROUP_END | JSON_SYNTAX::_T_NEXT;
jts.set_flags(myf);
} do { //整数部分
_Number = _Number * 10 + (jts.c - '0');
jtsnext();
} while (jts.s & JSON_SYNTAX::_T_NUMBER); if (jts.c == '.') {
//小数点之后的数字
factor = 1.0;
jts.set_flags(JSON_SYNTAX::_T_NUMBER);
jtsnext();
myf ^= JSON_SYNTAX::_T_DECIMAL;//之后不再允许小数点
jts.set_flags(myf); do {
factor *= 0.1;
_Number += (jts.c - '0') * factor;
jtsnext();
} while (jts.s & JSON_SYNTAX::_T_NUMBER);
} if ((jts.c | 32) == 'e') {
//科学计数的处理
unsigned int expo = 0;//指数
factor = 10.0;//因数
//e之后,必须是+-或者数字,如果是+-,那么后面必须是一个数字
//这里是json唯一允许+号出现的地方
jts.set_flags(JSON_SYNTAX::_T_NUMBER | JSON_SYNTAX::_T_NEGATIVE | JSON_SYNTAX::_T_POSITIVE);
jtsnext();
if (jts.c == '-') {
jts.set_flags(JSON_SYNTAX::_T_NUMBER);
jtsnext();
factor = 0.1;
}
else if (jts.c == '+') {
jts.set_flags(JSON_SYNTAX::_T_NUMBER);
jtsnext();
} jts.set_flags(JSON_SYNTAX::_T_NUMBER |
JSON_SYNTAX::_T_SPACE | JSON_SYNTAX::_T_OBJECT_END | JSON_SYNTAX::_T_GROUP_END | JSON_SYNTAX::_T_NEXT);
do {
expo = 10 * expo + (jts.c - '0');
jtsnext();
} while (jts.s & JSON_SYNTAX::_T_NUMBER); for (;;) {
//根据指数计算因数的快速求幂的方法
if (expo & 1)
_Number *= factor;
if ((expo >>= 1) == 0)
break;
factor *= factor;
}
} if (!(jts.s & JSON_SYNTAX::_T_SPACE))//非空白字符时,倒退到上一个字符,由此处判断一下会由微小的性能提升,毕竟一次jtsnext()的代价更高一些
--jts.index;
tree->new_var_number(cur, name_off, (jnumber_t)(neg ? -_Number : _Number));
} void j_true() {
jts.set_flags(JSON_SYNTAX::_T_BOOL);
for (int i = 0; i < 3; i++) {
jtsnext();
if ("rue"[i] != jts.c) {
err_pos = jts.index - 1;
longjmp(_Rem, -1);
}
}
tree->new_var_boolean(cur, name_off, true);
} void j_false() {
jts.set_flags(JSON_SYNTAX::_T_BOOL);
for (int i = 0; i < 4; i++) {
jtsnext();
if ("alse"[i] != jts.c) {
err_pos = jts.index - 1;
longjmp(_Rem, -1);
}
}
tree->new_var_boolean(cur, name_off, false);
} void j_null() {
jts.set_flags(JSON_SYNTAX::_T_NULL);
for (int i = 0; i < 3; i++) {
jtsnext();
if ("ull"[i] != jts.c) {
err_pos = jts.index - 1;
longjmp(_Rem, -1);
}
}
tree->new_var_null(cur, name_off);
} void j_value() {
jts.set_flags(
JSON_SYNTAX::_T_SPACE | // 空白字符
JSON_SYNTAX::_T_TEXT | // "
JSON_SYNTAX::_T_OBJECT_BEGIN | // {
JSON_SYNTAX::_T_GROUP_BEGIN | // [
JSON_SYNTAX::_T_NUMBER | // 0-9
JSON_SYNTAX::_T_NEGATIVE | // -负号
JSON_SYNTAX::_T_BOOL_BEGIN | // true false开头
JSON_SYNTAX::_T_NULL_BEGIN
); bool ok = false;
do { jtsnext(); } while (jts.s & JSON_SYNTAX::_T_SPACE); switch (jts.c) {
case '"':
j_text();
break;
case '{':
j_object();
break;
case '[':
j_group();
break;
case '-':
j_number();
break;
case 't':
j_true();
break;
case 'f':
j_false();
break;
case 'n':
j_null();
break;
default:
if (jts.s & JSON_SYNTAX::_T_NUMBER) {
j_number();
break;
}
break;
}
} void j_group() {
// [ 之后,允许空白字符,"{0-9] true false null
auto f = jts.set_flags(
JSON_SYNTAX::_T_SPACE | // 空白字符
JSON_SYNTAX::_T_TEXT | // "
JSON_SYNTAX::_T_OBJECT_BEGIN | // {
JSON_SYNTAX::_T_GROUP_END | // ]
JSON_SYNTAX::_T_NUMBER | // 0-9
JSON_SYNTAX::_T_NEGATIVE | // -负号
JSON_SYNTAX::_T_BOOL_BEGIN | // t f
JSON_SYNTAX::_T_NULL_BEGIN | // n
JSON_SYNTAX::_T_GROUP_BEGIN // 在遇到[时就递归前进
); auto _Node = cur;
cur = tree->new_node(cur, name_off, aqx::jsvt_group);
bool ok = false; do {
jtsnext(); switch (jts.c) {
case '"':
j_text();
jts.set_flags(JSON_SYNTAX::_T_SPACE | JSON_SYNTAX::_T_NEXT | JSON_SYNTAX::_T_GROUP_END);
break;
case '{':
j_object();
jts.set_flags(JSON_SYNTAX::_T_SPACE | JSON_SYNTAX::_T_NEXT | JSON_SYNTAX::_T_GROUP_END);
break;
case '[':
j_group();
jts.set_flags(JSON_SYNTAX::_T_SPACE | JSON_SYNTAX::_T_NEXT | JSON_SYNTAX::_T_GROUP_END);
break;
case '-':
j_number();
jts.set_flags(JSON_SYNTAX::_T_SPACE | JSON_SYNTAX::_T_NEXT | JSON_SYNTAX::_T_GROUP_END);
break;
case 't':
j_true();
jts.set_flags(JSON_SYNTAX::_T_SPACE | JSON_SYNTAX::_T_NEXT | JSON_SYNTAX::_T_GROUP_END);
break;
case 'f':
j_false();
jts.set_flags(JSON_SYNTAX::_T_SPACE | JSON_SYNTAX::_T_NEXT | JSON_SYNTAX::_T_GROUP_END);
break;
case 'n':
j_null();
jts.set_flags(JSON_SYNTAX::_T_SPACE | JSON_SYNTAX::_T_NEXT | JSON_SYNTAX::_T_GROUP_END);
break;
case ']':
ok = true;
break;
case ',':
jts.set_flags(
JSON_SYNTAX::_T_SPACE | // 空白字符
JSON_SYNTAX::_T_TEXT | // "
JSON_SYNTAX::_T_OBJECT_BEGIN | // {
JSON_SYNTAX::_T_NUMBER | // 0-9
JSON_SYNTAX::_T_NEGATIVE | // -负号
JSON_SYNTAX::_T_BOOL_BEGIN | // t f
JSON_SYNTAX::_T_NULL_BEGIN | // n
JSON_SYNTAX::_T_GROUP_BEGIN // 在遇到[时就递归前进
);
break;
default:
if (jts.s & JSON_SYNTAX::_T_NUMBER) {
j_number();
break;
}
break;
}
} while (!ok); jts.set_flags(f);
cur = _Node;
} void j_object() {
auto _Node = cur;
cur = tree->new_node(cur, name_off, aqx::jsvt_object);
auto f = jts.set_flags(JSON_SYNTAX::_T_TEXT | JSON_SYNTAX::_T_SPACE | JSON_SYNTAX::_T_OBJECT_END);
bool ok = false;
do {
jtsnext();
switch (jts.c) {
case '"':
j_text(true);
//名称字符串结束后,只允许 : 和 空白字符
jts.set_flags(JSON_SYNTAX::_T_VALUE | JSON_SYNTAX::_T_SPACE);
break;
case ':':
j_value();
jts.set_flags(JSON_SYNTAX::_T_TEXT | JSON_SYNTAX::_T_SPACE | JSON_SYNTAX::_T_OBJECT_END | JSON_SYNTAX::_T_NEXT);
break;
case ',':
// 碰到逗号时,新的一轮开始,但此时不再允许花括号,也就是不允许{"a":1,}这样的
jts.set_flags(JSON_SYNTAX::_T_TEXT | JSON_SYNTAX::_T_SPACE);
break;
case '}':
ok = true;
break;
}
} while (!ok);
cur = _Node;
} int j_root(bool _MultiRoot) {
if (setjmp(_Rem)) {
tree->clear();
return -1;
} root = tree->new_root();
cur = root;
name_off = _jnf;
err_pos = 0;
jts.set_flags(JSON_SYNTAX::_T_OBJECT_BEGIN | JSON_SYNTAX::_T_GROUP_BEGIN | JSON_SYNTAX::_T_SPACE);
for (;;) {
jtsnext();
if (jts.c == '{') {
j_object();
break;
}
else if (jts.c == '[') {
j_group();
break;
}
} if (!_MultiRoot) {
jts.open_instr();
for (;;) {
if (jts.index >= jts.size)
break; char _Chr = jts.text[jts.index++];
if (!_Chr)
break; if (!(json_char_state[(unsigned char)_Chr] & JSON_SYNTAX::_T_SPACE)) {
err_pos = jts.index - 1;
//tree->clear();
return -1;
}
}
}
return 0;
} private:
jmp_buf _Rem;
_Ty jts;
_json_tree *tree;
jsize_t cur;
jsize_t root;
jsize_t name_off;
jsize_t err_pos;
}; } using json_tree = aqx_internal::_json_tree; template<typename _Ty>
using json_parser_t = aqx_internal::_json_parser<_Ty>; using jts_gbk = aqx_internal::_jts_gbk;
using jts_utf8 = aqx_internal::_jts_utf8; } /* //我已经把代码移植到C去了,最终我还是又回到C++来使用它,因为。。。C的性能,反而不如C++,无论是vc还是gcc都是不如c++...
//可能的原因是我对C的二进制优化的手法并不纯熟而导致的问题,完全照搬结构大概是不合理的做法,
//不过我认为更多的可能性还是,C入栈的参数比C++要多而导致的。
//毕竟,this指针总在cx si之间传,而C,要写入太多太多结构指针 //下面这一串是构建字符状态表的代码 int sztext[128];
memset(sztext, 0, 512); sztext['\"'] = aqx::aqx_internal::JSON_SYNTAX::_T_TEXT | aqx::aqx_internal::JSON_SYNTAX::_T_ESCAPE_TYPE;
sztext[':'] = aqx::aqx_internal::JSON_SYNTAX::_T_VALUE;
sztext[','] = aqx::aqx_internal::JSON_SYNTAX::_T_NEXT;
sztext['{'] = aqx::aqx_internal::JSON_SYNTAX::_T_OBJECT_BEGIN;
sztext['}'] = aqx::aqx_internal::JSON_SYNTAX::_T_OBJECT_END;
sztext['['] = aqx::aqx_internal::JSON_SYNTAX::_T_GROUP_BEGIN;
sztext[']'] = aqx::aqx_internal::JSON_SYNTAX::_T_GROUP_END;
sztext['\\'] = aqx::aqx_internal::JSON_SYNTAX::_T_ESCAPE_BEGIN | aqx::aqx_internal::JSON_SYNTAX::_T_ESCAPE_TYPE;
sztext['n'] = aqx::aqx_internal::JSON_SYNTAX::_T_ESCAPE_TYPE;
sztext['r'] = aqx::aqx_internal::JSON_SYNTAX::_T_ESCAPE_TYPE;
sztext['t'] = aqx::aqx_internal::JSON_SYNTAX::_T_ESCAPE_TYPE;
sztext['b'] = aqx::aqx_internal::JSON_SYNTAX::_T_ESCAPE_TYPE;
sztext['f'] = aqx::aqx_internal::JSON_SYNTAX::_T_ESCAPE_TYPE;
sztext['u'] = aqx::aqx_internal::JSON_SYNTAX::_T_ESCAPE_TYPE;
sztext['/'] = aqx::aqx_internal::JSON_SYNTAX::_T_ESCAPE_TYPE;
sztext['\n'] = aqx::aqx_internal::JSON_SYNTAX::_T_ENDL | aqx::aqx_internal::JSON_SYNTAX::_T_SPACE;
sztext['\r'] = aqx::aqx_internal::JSON_SYNTAX::_T_ENDL | aqx::aqx_internal::JSON_SYNTAX::_T_SPACE;
sztext[' '] = aqx::aqx_internal::JSON_SYNTAX::_T_SPACE;
sztext['\t'] = aqx::aqx_internal::JSON_SYNTAX::_T_SPACE; for (size_t i = 0; i < strlen("0123456789"); i++)
sztext["0123456789"[i]] = aqx::aqx_internal::JSON_SYNTAX::_T_NUMBER | aqx::aqx_internal::JSON_SYNTAX::_T_HEX;
for (size_t i = 0; i < strlen("abcdefABCDEF"); i++)
sztext["abcdefABCDEF"[i]] = aqx::aqx_internal::JSON_SYNTAX::_T_HEX; sztext['.'] = aqx::aqx_internal::JSON_SYNTAX::_T_DECIMAL; sztext['+'] = aqx::aqx_internal::JSON_SYNTAX::_T_POSITIVE;
sztext['-'] = aqx::aqx_internal::JSON_SYNTAX::_T_NEGATIVE;
sztext['e'] |= aqx::aqx_internal::JSON_SYNTAX::_T_E;
sztext['E'] |= aqx::aqx_internal::JSON_SYNTAX::_T_E; sztext['t'] |= aqx::aqx_internal::JSON_SYNTAX::_T_BOOL;
sztext['t'] |= aqx::aqx_internal::JSON_SYNTAX::_T_BOOL_BEGIN;
sztext['r'] |= aqx::aqx_internal::JSON_SYNTAX::_T_BOOL;
sztext['u'] |= aqx::aqx_internal::JSON_SYNTAX::_T_BOOL;
sztext['e'] |= aqx::aqx_internal::JSON_SYNTAX::_T_BOOL;
sztext['f'] |= aqx::aqx_internal::JSON_SYNTAX::_T_BOOL;
sztext['f'] |= aqx::aqx_internal::JSON_SYNTAX::_T_BOOL_BEGIN;
sztext['a'] |= aqx::aqx_internal::JSON_SYNTAX::_T_BOOL;
sztext['l'] |= aqx::aqx_internal::JSON_SYNTAX::_T_BOOL;
sztext['s'] |= aqx::aqx_internal::JSON_SYNTAX::_T_BOOL; sztext['n'] |= aqx::aqx_internal::JSON_SYNTAX::_T_NULL_BEGIN;
sztext['u'] |= aqx::aqx_internal::JSON_SYNTAX::_T_NULL;
sztext['l'] |= aqx::aqx_internal::JSON_SYNTAX::_T_NULL;
for (int y = 0; y < 8; y++)
{
for (int x = 0; x < 16; x++)
{
printf("%d,", sztext[y * 16 + x]);
} printf("\n");
} return 0; */

封装给lua使用的库:

//ljsonlib.h
#pragma once
#include "lua/lua.hpp"
#include "aqx/json.h" class ljson_convert {
public:
ljson_convert(lua_State *_s, int ec);
int table_to_json(int n);
int json_to_table(const char *_Text, int _Len); private:
friend int lua_table_to_json(lua_State *s);
void json_to_object(aqx::jsize_t _Ref);
void json_to_group(aqx::jsize_t _Ref);
int ec_mode;
aqx::json_tree jt;
aqx::json_parser_t<aqx::jts_gbk> *pgbk;
aqx::json_parser_t<aqx::jts_utf8> *putf8;
lua_State *s;
std::string b;
}; //_CharEncoding为字符编码格式,默认为"gbk",可以传入"utf8"
ljson_convert *lua_openljsonlib(lua_State *s, const char *_CharEncoding = "");
//ljsonlib.cpp
#include "pch.h"
#include "ljsonlib.h" #define lua_isintnum(_Number_) (_Number_ - floor(_Number_) < 1e-6) ljson_convert::ljson_convert(lua_State *_s, int ec) {
s = _s;
jt.reserve(0x1000, 0x400);
b.reserve(0x1000);
ec_mode = ec;
if (!ec_mode)
pgbk = new aqx::json_parser_t<aqx::jts_gbk>(jt);
else
putf8 = new aqx::json_parser_t<aqx::jts_utf8>(jt);
} int ljson_convert::table_to_json(int n) {
char sznum[128];
lua_pushnil(s);
int t = 0;
if (!lua_next(s, n))
return 0; switch (lua_type(s, -2)) {
case LUA_TNUMBER:
b += '[';
t = 2;
break;
case LUA_TSTRING:
b += "{\"";
b += lua_tostring(s, -2);
b += "\":";
t = 1;
break;
default:
lua_pop(s, 1);
return -1;
} switch (lua_type(s, -1)) {
case LUA_TBOOLEAN:
b += (lua_toboolean(s, -1) == 1) ? "true" : "false";
break;
case LUA_TNUMBER: {
double dv = lua_tonumber(s, -1);
if (lua_isintnum(dv))
sprintf_s(sznum, 128, "%I64d", (long long)dv);
else
sprintf_s(sznum, 128, "%lf", dv);
b += sznum;
break;
}
case LUA_TSTRING:
b += '"';
b += lua_tostring(s, -1);
b += '"';
break;
case LUA_TTABLE:
if (table_to_json(-2)) {
lua_pop(s, 1);
return -1;
}
break;
default:
lua_pop(s, 1);
return -1;
} lua_pop(s, 1);
while (lua_next(s, n)) { switch (lua_type(s, -2)) {
case LUA_TNUMBER:
b += ',';
break;
case LUA_TSTRING:
b += ",\"";
b += lua_tostring(s, -2);
b += "\":";
break;
default:
lua_pop(s, 1);
return -1;
} switch (lua_type(s, -1)) {
case LUA_TBOOLEAN:
b += (lua_toboolean(s, -1) == 1) ? "true" : "false";
break;
case LUA_TNUMBER: {
double dv = lua_tonumber(s, -1);
if (lua_isintnum(dv))
sprintf_s(sznum, 128, "%I64d", (long long)dv);
else
sprintf_s(sznum, 128, "%lf", dv);
b += sznum;
break;
}
case LUA_TSTRING:
b += '"';
b += lua_tostring(s, -1);
b += '"';
break;
case LUA_TTABLE:
if (table_to_json(-2)) {
lua_pop(s, 1);
return -1;
}
break;
default:
lua_pop(s, 1);
return -1;
} lua_pop(s, 1); } b += t == 1 ? '}' : ']';
return 0;
} int ljson_convert::json_to_table(const char *_Text, int _Len) {
if (!ec_mode)
{
if (!pgbk->load_string(_Text, _Len, true)) {
return -1;
}
}
else
{
if (!putf8->load_string(_Text, _Len, true))
return -1;
} auto root = jt.get_root();
if (!root)
return -1;
json_to_object(root->begin());
return 0;
} void ljson_convert::json_to_object(aqx::jsize_t _Ref) {
for (auto v = jt.get_val(_Ref); v != nullptr; v = v->next(jt)) {
switch (v->type()) {
case aqx::jsvt_null:
lua_pushstring(s, v->skey(jt));
lua_pushnil(s);
lua_settable(s, -3);
break;
case aqx::jsvt_string:
lua_pushstring(s, v->skey(jt));
lua_pushstring(s, v->tostring(jt));
lua_settable(s, -3);
break;
case aqx::jsvt_number:
{
lua_pushstring(s, v->skey(jt));
double dv = v->tonumber();
if (lua_isintnum(dv))
lua_pushinteger(s, (intptr_t)dv);
else
lua_pushnumber(s, dv);
lua_settable(s, -3);
break;
}
case aqx::jsvt_boolean:
lua_pushstring(s, v->skey(jt));
lua_pushboolean(s, v->toboolean());
lua_settable(s, -3);
break;
case aqx::jsvt_object: {
auto n = v->toobject(jt);
if (!n->size())
break;
lua_pushstring(s, v->skey(jt));
lua_newtable(s);
json_to_object(n->begin());
lua_settable(s, -3);
break;
}
case aqx::jsvt_group: {
auto n = v->toobject(jt);
if (!n->size()) {
break;
}
lua_pushstring(s, v->skey(jt));
lua_newtable(s);
json_to_group(n->begin());
lua_settable(s, -3);
break;
}
} }
} void ljson_convert::json_to_group(aqx::jsize_t _Ref) {
int i = 1; for (auto v = jt.get_val(_Ref); v != nullptr; v = v->next(jt)) {
switch (v->type()) {
case aqx::jsvt_null:
lua_pushnil(s);
lua_rawseti(s, -2, i++);
break;
case aqx::jsvt_string:
lua_pushstring(s, v->tostring(jt));
lua_rawseti(s, -2, i++);
break;
case aqx::jsvt_number: {
double dv = v->tonumber();
if (lua_isintnum(dv))
lua_pushinteger(s, (intptr_t)dv);
else
lua_pushnumber(s, dv);
lua_rawseti(s, -2, i++);
break;
}
case aqx::jsvt_boolean:
lua_pushboolean(s, v->toboolean());
break;
case aqx::jsvt_object: {
auto n = v->toobject(jt);
if (!n->size())
break;
lua_newtable(s);
json_to_object(n->begin());
lua_rawseti(s, -2, i++);
break;
}
case aqx::jsvt_group: {
auto n = v->toobject(jt);
if (!n->size())
break;
lua_newtable(s);
json_to_group(n->begin());
lua_rawseti(s, -2, i++);
break;
}
} }
} ljson_convert *get_ljson_convert(lua_State *s) {
lua_getglobal(s, "__ljsonlib_convert_");
if (lua_isnil(s, -1))
return nullptr;
return (ljson_convert*)lua_touserdata(s, -1);
} int lua_table_to_json(lua_State *s)
{
ljson_convert *pjc = get_ljson_convert(s);
if (!pjc)
return 0;
if (!lua_gettop(s))
return 0;
if (lua_type(s, 1) != LUA_TTABLE)
return 0;
pjc->b.clear();
if (pjc->table_to_json(1)) {
pjc->b.clear();
}
lua_pushstring(s, pjc->b.c_str());
return 1;
} int lua_table_from_json(lua_State *s) {
ljson_convert *pjc = get_ljson_convert(s);
if (!pjc)
return 0;
if (!lua_gettop(s))
return 0;
if (lua_type(s, 1) != LUA_TSTRING)
return 0;
lua_newtable(s); if (!pjc->json_to_table(lua_tostring(s, 1), -1)) {
return 1;
} lua_pop(s, 1);
return 0;
} ljson_convert *lua_openljsonlib(lua_State *s, const char *_CharEncoding)
{
ljson_convert *pjc = get_ljson_convert(s);
if (pjc)return pjc;
pjc = new ljson_convert(s, (strstr(_CharEncoding, "utf") == nullptr) ? 0 : 1);
lua_pushlightuserdata(s, pjc);
lua_setglobal(s, "__ljsonlib_convert_"); lua_getglobal(s, "table");
lua_pushcfunction(s, lua_table_to_json);
lua_setfield(s, -2, "tojson"); lua_pushcfunction(s, lua_table_from_json);
lua_setfield(s, -2, "fromjson"); return pjc;
}
// ConsoleApplication2.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
// #include "pch.h"
#include <thread>
#include <iostream>
#pragma comment(lib, "lua54.lib")
#include "lxsharelib.h"
#include "ljsonlib.h"
int main(int argc, char **argv)
{
lua_State *s = luaL_newstate();
luaL_openlibs(s); //使用这个接口,向lua本身的table对象中,添加两个函数table.tojson和table.fromjson
auto p = lua_openljsonlib(s, "");//第2个参数可以传入"utf8"来应对utf8的lua文件,默认的情况下是gbk
if (luaL_dofile(s, "G:\\vs2017\\ConsoleApplication2\\x64\\Release\\script\\testjson.lua"))
printf("%s\n", lua_tostring(s, -1));
lua_close(s); //用完之后,需要自己释放掉内存,这个问题没什么好办法解决,除非扩展到lua源码中,或者给lua_close实现回调
delete p; return 0;
}

测试脚本代码:

-- testjson.lua

local t = {
x = 3.14159,
y = 2,
z = {10,20,30,40,50}
}; local json_text = table.tojson(t);
print(json_text);--{"z":[10,20,30,40,50],"y":2,"x":3.141590} local t2 = table.fromjson('{"a":1.21e-3,"b":2,"c":[3,4,5,6,7,"abcde"],"d":[]}'); print(t2)
--[[
b:2
a:0.00121
c:table: 000001C74BABABE0
]]
for i, e in pairs(t2) do
print(i..':'..tostring(e));
end --[[
1:3
2:4
3:5
4:6
5:7
6:abcde
]]
for i, e in ipairs(t2.c) do
print(i..':'..e);
end

{"y":2,"x":3.141590,"z":[10,20,30,40,50]}
table: 0000025A15D5EFC0
a:0.00121
c:table: 0000025A15D7A340
b:2
1:3
2:4
3:5
4:6
5:7
6:abcde

最新文章

  1. Jquery制作--美化下拉框
  2. Cocos2d-x游戏引擎实战开发炸弹超人项目教程 全套下载 1至6课
  3. PHP调用webservice遇到 Soap WSDL Error - &quot;failed to load external entity
  4. CentOS 6.5 x86_64系统手动释放内存
  5. JavaScript(七)——视频插入
  6. GameObject.Instantiate(游戏体的实例化),角色的选择
  7. 《Struts2.x权威指南》学习笔记2
  8. localStorage的一些简单的操作
  9. CSS 边框
  10. tarjan缩点
  11. 关于jq操作table下多个type=radio的input的选中
  12. mysql基础:列类型--整型
  13. CoreCRM 开发实录 —— 单元测试、测试驱动开发和在线服务
  14. Java反射机制小结和实际操作
  15. 使用POI导出Excel文件
  16. SQL语句——重复记录
  17. [转载]FileStream读写文件
  18. org.postgresql.util.PSQLException: 栏位索引超过许可范围:3,栏位数:2。
  19. C++知识整理(在此感谢大牛的整理)
  20. 五子棋项目总结 JavaScript+jQuery(插件写法)+bootstrap(模态框)

热门文章

  1. Git新建本地分支
  2. Tarjan算法 求 有向图的强连通分量
  3. HTML基础-3
  4. 前端需要了解的颜色模型,RGB、HSL和HSV
  5. Linux部署Apollo+.Net Core简单使用
  6. 【Go语言学习笔记】为什么要选择Go语言
  7. vue+elementUI中单选框el-radio设置默认值和唯一标识某个单选框
  8. 【GIS】GeoServer服务Authkey配置记录
  9. vscode输出窗口中文乱码
  10. RocketMQ源码详解 | Consumer篇 &#183; 其一:消息的 Pull 和 Push