使用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] == '\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();

            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] == '\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<String, String> 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<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] == '\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。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM