zoukankan      html  css  js  c++  java
  • 使用c#解析json库

    写了个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[0] == '
    ' || key[0] == '	')
                                {
                                    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] == '
    ' || key[0] == '	')
                                {
                                    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();
    
                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[0] == '
    ' || value[0] == '	')
                    {
                        value = value.Substring(1, value.Length - 1);
                    }
                    String v = value;
                    key = key.Trim();
                    while (key[0] == '
    ' || key[0] == '	')
                    {
                        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<String, String> parsearray = (String _c) =>
                {
                    value = value.Trim();
    
                    if (value == "")
                    {
                        return _c;
                    }
    
                    while (value[0] == '
    ' || value[0] == '	')
                    {
                        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<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 = 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] == '
    ' || key[0] == '	')
                                {
                                    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] == '
    ' || key[0] == '	')
                                {
                                    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。

  • 相关阅读:
    UVa 1354 天平难题 (枚举二叉树)
    广西邀请赛总结
    UVa 12118 检查员的难题 (dfs判连通, 构造欧拉通路)
    UVA
    Uva 127 "Accordian" Patience (模拟)
    UVA 10539 Almost Prime Numbers( 素数因子)
    HDU 1272 小希的迷宫(并查集)
    HDU 1213 How Many Tables (并查集)
    POJ 2236 Wireless Network(并查集)
    HDU 1233 还是畅通工程 ( Kruskal或Prim)
  • 原文地址:https://www.cnblogs.com/qianqians/p/4501877.html
Copyright © 2011-2022 走看看