• 使用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。

  • 相关阅读:
    游泳池 (Standard IO)
    Antimonotonicity (Standard IO)
    开花 (Standard IO)
    Wild Number (Standard IO)
    数码问题 (Standard IO)
    输油管道 (Standard IO)
    猴子摘桃 (Standard IO)
    二叉树 (Standard IO)
    iis运行asp.net页面提示“服务器应用程序不可用”的解决办法_.NET.
    SVN安装配置与使用
  • 原文地址:https://www.cnblogs.com/qianqians/p/4501877.html
Copyright © 2020-2023  润新知