写了个c#版的json解析库,提供了json到hashtable以及hashtable到json字符串的转换
受惠于c#的语法特性,hashtable到json的解析变得非常简单
先判断传入的object的类型,如果是hashtable或者array,则循环遍历,并且将元素转成字符串
得益于c#的语法,元素到字符串的转换可以以
Convert.ToString(value);
的方式简单完成.
整个hashtable到json串的转换代码如下:
public static String pack(object dict) { Func
可以如我在c++中惯用的做法一样,通过匿名函数将对hashtable,array以及其他值类型的转换分别拆分成了3个lambda对象parsevalue,parselist,parsedict.
对于json串转array或hashtable则稍微复杂,考虑到需要区分json是一个array([])还是hashtable({}),所以在删除了字符串前面的空格,table符号,以及其他无意义的符号之后首先判断了第一个字符串是"{"还是"[",并且进入对应的分支
if (c.Current.ToString() == "{ ") { parsesys = parsekey; parseenum = parsemap; Hashtable _newtable = new Hashtable(); if (_table != null) { key = key.Trim(); while (key[0] == '\n' || key[0] == '\t') { key = key.Substring(1, key.Length - 1); } s.Push(_table); key = key.Substring(1, key.Length - 2); _table[key] = _newtable; _table = null; key = ""; } else if (_array != null) { s.Push(_array); _array.Add(_newtable); _array = null; } _table = _newtable; continue; } if (c.Current.ToString() == "}") { parseenum(c.Current.ToString()); if (s.Count > 0) { parsepop(s.Pop()); } continue; } if (c.Current.ToString() == "[") { parsesys = parsevalue; parseenum = parsearray; ArrayList _newarray = new ArrayList(); if (_table != null) { s.Push(_table); key = key.Trim(); while (key[0] == '\n' || key[0] == '\t') { key = key.Substring(1, key.Length - 1); } key = key.Substring(1, key.Length - 2); _table[key] = _newarray; _table = null; key = ""; } else if (_array != null) { s.Push(_array); _array.Add(_newarray); _array = null; } _array = _newarray; continue; } if (c.Current.ToString() == "]") { parseenum(c.Current.ToString()); parsepop(s.Pop()); continue; }
然后整个对字符串的遍历过程,考虑json采用","分割元素,dict以及list都是,dict的元素是pair,对于pair采用":"分割key和value,而字符串则以""包括,所以我采用一个count计数来记录字符串中出现的"的次数,并且考虑到字符串中也有引号但是是以转义的方式比如"a\"1"的形式存在,所以用一个escape 记录出现的转义符
int count = 0; int escape = 0; while (c.MoveNext()) { if (c.Current.ToString() == "\\"){ escape = 1; }else{ escape = 0; } if (c.Current.ToString() == "\"" && escape != 1) { if (count == 0) { count++; } else { count = 0; } }
如此即可正确的识别当前字符是否是在一个字符串值中比如key或者类型为string的value
如果不是,即可按"," ":" "{" "}" "[" "]"这些json的语义符号的语义做语法处理,以此实现one pass解析json字符串。
然后考虑在解析时,会出现{},[]之间的嵌套,所以会在读取到{,[的时候分别创建新的hashtable或是array,并且将老的容器填入到一个stack中去,在读取到结束符号}或者]后,对stack做pop得到嵌套的上一层容器,并且对字符串做后续的解析。
整个解析字符串的代码如下:
public static object unpack(String jsonstr) { object _out = null; Hashtable _table = null; ArrayList _array = null; String key = ""; String value = ""; CharEnumerator c = jsonstr.GetEnumerator(); Stack s = new Stack(); Funcparsekey = (String _c) =>{ key += _c; return key; }; Func parsevalue = (String _c) => { value += _c; return value; }; Func parsesys = parsekey; Func parsemap = (String _c) => { parsesys = parsekey; if (value == "" || key == "") { return _c; } value = value.Trim(); while (value[0] == '\n' || value[0] == '\t') { value = value.Substring(1, value.Length - 1); } String v = value; key = key.Trim(); while (key[0] == '\n' || key[0] == '\t') { key = key.Substring(1, key.Length - 1); } key = key.Substring(1, key.Length - 2); if (v == "true") { _table[key] = true; } else if (v == "false") { _table[key] = false; } else if (v == "null") { _table[key] = null; } else { if (v[0] == '\"' && v[v.Length - 1] == '\"') { v = v.Substring(1, v.Length - 2); _table[key] = v; } else { int status = 0; foreach (char _ch in v) { if ((_ch < '0' || _ch > '9') && _ch != '.') { throw new Exception("format error"); } if (_ch == '.') { status++; } } if (status == 0) { _table[key] = Convert.ToInt64(v); } else if (status == 1) { _table[key] = Convert.ToDouble(v); } else { throw new Exception("format error"); } } } key = ""; value = ""; return _c; }; Func parsearray = (String _c) => { value = value.Trim(); if (value == "") { return _c; } while (value[0] == '\n' || value[0] == '\t') { value = value.Substring(1, value.Length - 1); } String v = value; if (v.ToLower() == "true") { _array.Add(true); } else if (v.ToLower() == "false") { _array.Add(false); } else if (v.ToLower() == "null") { _array.Add(null); } else { if (v[0] == '\"' && v[v.Length - 1] == '\"') { v = v.Substring(1, v.Length - 2); _array.Add(v); } else { int status = 0; foreach (char _ch in v) { if ((_ch < '0' || _ch > '9') && _ch != '.') { throw new Exception("format error"); } if (_ch == '.') { status++; } } if (status == 0) { _array.Add(Convert.ToInt64(v)); } else if (status == 1) { _array.Add(Convert.ToDouble(v)); } else { throw new Exception("format error"); } } } key = ""; value = ""; return _c; }; Func parseenum = parsemap; Func parsepop = (object o) =>{ if (o.GetType() == typeof(Hashtable)) { _table = (Hashtable)o; parsesys = parsekey; parseenum = parsemap; } else if (o.GetType() == typeof(ArrayList)) { _array = (ArrayList)o; parsesys = parsevalue; parseenum = parsearray; } return o; }; int count = 0; int escape = 0; while (c.MoveNext()) { if (c.Current.ToString() == "\\"){ escape = 1; }else{ escape = 0; } if (c.Current.ToString() == "\"" && escape != 1) { if (count == 0) { count++; } else { count = 0; } } if (count == 0) { if (c.Current.ToString() == "{ ") { parsesys = parsekey; parseenum = parsemap; Hashtable _newtable = new Hashtable(); if (_table != null) { key = key.Trim(); while (key[0] == '\n' || key[0] == '\t') { key = key.Substring(1, key.Length - 1); } s.Push(_table); key = key.Substring(1, key.Length - 2); _table[key] = _newtable; _table = null; key = ""; } else if (_array != null) { s.Push(_array); _array.Add(_newtable); _array = null; } _table = _newtable; continue; } if (c.Current.ToString() == "}") { parseenum(c.Current.ToString()); if (s.Count > 0) { parsepop(s.Pop()); } continue; } if (c.Current.ToString() == "[") { parsesys = parsevalue; parseenum = parsearray; ArrayList _newarray = new ArrayList(); if (_table != null) { s.Push(_table); key = key.Trim(); while (key[0] == '\n' || key[0] == '\t') { key = key.Substring(1, key.Length - 1); } key = key.Substring(1, key.Length - 2); _table[key] = _newarray; _table = null; key = ""; } else if (_array != null) { s.Push(_array); _array.Add(_newarray); _array = null; } _array = _newarray; continue; } if (c.Current.ToString() == "]") { parseenum(c.Current.ToString()); parsepop(s.Pop()); continue; } if (c.Current.ToString() == ",") { parseenum(c.Current.ToString()); continue; } if (c.Current.ToString() == ":") { parsesys = parsevalue; continue; } } parsesys(c.Current.ToString()); } if (_table != null) { _out = _table; } else if (_array != null) { _out = _array; } return _out; }
代码地址: https://github.com/qianqians/jsonparse/blob/master/JsonParser.cs
这份代码,目前还是只是在一个很小的unity项目中使用,希望更多的朋友使用并提交bug。