使用c#解析json库

时间:2021-10-25 04:48:25

写了个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<object, String> parsevalue = (object value) =>
{
String _out = "";
if (value.GetType() == typeof(String))
{
_out += "\"";
}
_out += Convert.ToString(value);
if (value.GetType() == typeof(String))
{
_out += "\"";
}
return _out;
}; Func<Array, String> parselist = (Array _array) =>
{
String _out = "]";
foreach (Object o in _array)
{
if ((o.GetType() == typeof(Hashtable)) || (o.GetType() == typeof(Array)))
{
_out += pack(o);
}
else
{
_out += parsevalue(o);
}
_out += ",";
}
_out.Remove(_out.Length - 1);
_out += "]"; return _out;
}; Func<Hashtable, String> parsedict = (Hashtable _dict) =>{
String _out = "{";
foreach (System.Collections.DictionaryEntry _obj in _dict)
{
_out += "\"" + Convert.ToString(_obj.Key) + "\"";
_out += ":";
if ((_obj.Value.GetType() == typeof(Hashtable)) || (_obj.Value.GetType() == typeof(Array)))
{
_out += pack(_obj.Value);
}
else
{
_out += parsevalue(_obj.Value);
}
_out += ",";
}
_out.Remove(_out.Length - 1);
_out += "}"; return _out;
}; Func<object, String> parse = (object o) =>
{
if (o.GetType() == typeof(Hashtable))
{
return parsedict((Hashtable)o);
}
else if (o.GetType() == typeof(Array))
{
return parselist((Array)o);
}
                else
                {
throw new System.Exception("can not parse this object to json");
                }
}; return parse(dict);
}

可以如我在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[] == '\n' || key[] == '\t')
{
key = key.Substring(, key.Length - );
}
s.Push(_table);
key = key.Substring(, key.Length - );
_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 > )
{
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[] == '\n' || key[] == '\t')
{
key = key.Substring(, key.Length - );
}
key = key.Substring(, key.Length - );
_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 = ;
int escape = ;
while (c.MoveNext())
{
if (c.Current.ToString() == "\\"){
escape = ;
}else{
escape = ;
} if (c.Current.ToString() == "\"" && escape != )
{
if (count == )
{
count++;
}
else
{
count = ;
}
}

如此即可正确的识别当前字符是否是在一个字符串值中比如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(); Func<String, String> parsekey = (String _c) =>{
key += _c;
return key;
}; Func<String, String> parsevalue = (String _c) =>
{
value += _c;
return value;
}; Func<String, String> parsesys = parsekey; Func<String, String> parsemap = (String _c) =>
{
parsesys = parsekey; if (value == "" || key == "")
{
return _c;
} value = value.Trim();
while (value[] == '\n' || value[] == '\t')
{
value = value.Substring(, value.Length - );
}
String v = value;
key = key.Trim();
while (key[] == '\n' || key[] == '\t')
{
key = key.Substring(, key.Length - );
}
key = key.Substring(, key.Length - ); if (v == "true")
{
_table[key] = true;
}
else if (v == "false")
{
_table[key] = false;
}
else if (v == "null")
{
_table[key] = null;
}
else
{
if (v[] == '\"' && v[v.Length - ] == '\"')
{
v = v.Substring(, v.Length - );
_table[key] = v;
}
else
{
int status = ; foreach (char _ch in v)
{
if ((_ch < '' || _ch > '') && _ch != '.')
{
throw new Exception("format error");
} if (_ch == '.')
{
status++;
}
} if (status == )
{
_table[key] = Convert.ToInt64(v);
}
else if (status == )
{
_table[key] = Convert.ToDouble(v);
}
else
{
throw new Exception("format error");
}
} } key = "";
value = ""; return _c;
}; Func<String, String> parsearray = (String _c) =>
{
value = value.Trim(); if (value == "")
{
return _c;
} while (value[] == '\n' || value[] == '\t')
{
value = value.Substring(, value.Length - );
}
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[] == '\"' && v[v.Length - ] == '\"')
{
v = v.Substring(, v.Length - );
_array.Add(v);
}
else
{
int status = ; foreach (char _ch in v)
{
if ((_ch < '' || _ch > '') && _ch != '.')
{
throw new Exception("format error");
} if (_ch == '.')
{
status++;
}
} if (status == )
{
_array.Add(Convert.ToInt64(v));
}
else if (status == )
{
_array.Add(Convert.ToDouble(v));
}
else
{
throw new Exception("format error");
}
} } key = "";
value = ""; return _c;
}; Func<String, String> parseenum = parsemap; Func<object, object> 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 = ;
int escape = ;
while (c.MoveNext())
{
if (c.Current.ToString() == "\\"){
escape = ;
}else{
escape = ;
} if (c.Current.ToString() == "\"" && escape != )
{
if (count == )
{
count++;
}
else
{
count = ;
}
} if (count == )
{
if (c.Current.ToString() == "{")
{
parsesys = parsekey;
parseenum = parsemap; Hashtable _newtable = new Hashtable();
if (_table != null)
{
key = key.Trim();
while (key[] == '\n' || key[] == '\t')
{
key = key.Substring(, key.Length - );
}
s.Push(_table);
key = key.Substring(, key.Length - );
_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 > )
{
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[] == '\n' || key[] == '\t')
{
key = key.Substring(, key.Length - );
}
key = key.Substring(, key.Length - );
_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。