用C#實現(xiàn)一個JSON解釋器

[原創(chuàng)]
https://www.cnblogs.com/gangjian/p/14386552.html

public class JSONReader
{
    // 從文件讀出JSON對象
    public static JSONObject Read(string path)
    {
        if (!File.Exists(path))
        {
            return null;
        }
        try
        {
            string txt = File.ReadAllText(path);
            int offset = 0;
            JSONObject obj = null;
            if (JSONObject.TryParse(txt, ref offset, out obj))
            {
                return obj;
            }
        }
        catch (Exception)
        {
        }
        return null;
    }
}

public class JSONObject
{
    // JSON對象
    List<JSONPair> _pairs = new List<JSONPair>();            // '名稱:值'對list
    private JSONObject(List<JSONPair> pair_list)
    {
        this._pairs = pair_list;
    }

    public static bool TryParse(string in_str, ref int offset, out JSONObject obj)
    {
        obj = null;
        int idx = offset;
        char? ch = Util.GetNextNsChar(in_str, ref idx);
        if (null == ch
            || !ch.Equals('{'))
        {
            return false;
        }
        idx += 1;
        List<JSONPair> pair_list = new List<JSONPair>();
        while (true)
        {
            JSONPair pair;
            if (JSONPair.TryParse(in_str, ref idx, out pair))
            {
                pair_list.Add(pair);
                idx += 1;
            }
            ch = Util.GetNextNsChar(in_str, ref idx);
            if (null != ch)
            {
                if (ch.Equals('}'))
                {
                    // 結(jié)束
                    obj = new JSONObject(pair_list);
                    offset = idx;
                    return true;
                }
                else if (ch.Equals(','))
                {
                    idx += 1;
                    continue;
                }
            }
            break;
        }
        return false;
    }
}

public class JSONArray
{
    // JSON數(shù)組
    List<JSONValue> _valList = new List<JSONValue>();
    internal List<JSONValue> ValueList
    {
        get { return _valList; }
    }
    private JSONArray(List<JSONValue> val_list)
    {
        this._valList = val_list;
    }

    public static bool TryParse(string in_str, ref int offset, out JSONArray array)
    {
        array = null;
        int idx = offset;
        char? ch = Util.GetNextNsChar(in_str, ref idx);
        if (null == ch
            || !ch.Equals('['))
        {
            return false;
        }
        idx += 1;
        List<JSONValue> val_list = new List<JSONValue>();
        while (true)
        {
            JSONValue val;
            if (JSONValue.TryParse(in_str, ref idx, out val))
            {
                val_list.Add(val);
                idx += 1;
            }
            ch = Util.GetNextNsChar(in_str, ref idx);
            if (null != ch)
            {
                if (ch.Equals(']'))
                {
                    // 結(jié)束
                    array = new JSONArray(val_list);
                    offset = idx;
                    return true;
                }
                else if (ch.Equals(','))
                {
                    idx += 1;
                    continue;
                }
            }
            break;
        }
        return false;
    }
}

public class JSONPair
{
    // '名稱:值'對
    string _name = string.Empty;
    object _value = null;
    private JSONPair(string name, JSONValue val)
    {
        this._name = name;
        this._value = val;
    }

    public static bool TryParse(string in_str, ref int offset, out JSONPair pair)
    {
        pair = null;
        int idx = offset;
        string name = Util.GetJsonStr(in_str, ref idx);
        if (null == name)
        {
            return false;
        }
        idx += 1;
        char? ch = Util.GetNextNsChar(in_str, ref idx);
        if (null == ch
            || !ch.Equals(':'))
        {
            return false;
        }
        idx += 1;
        JSONValue val;
        if (!JSONValue.TryParse(in_str, ref idx, out val))
        {
            return false;
        }
        pair = new JSONPair(name, val);
        offset = idx;
        return true;
    }
}

public class JSONValue
{
    // 字符串
    // 數(shù)字
    // JSONObject
    // JSONArray
    // true/false
    // null
    object _value = null;
    public object Value
    {
        get { return _value; }
    }
    string _category = string.Empty;
    public string Category
    {
        get { return _category; }
    }
    private JSONValue(string category, object val)
    {
        this._category = category;
        this._value = val;
    }

    public static bool TryParse(string in_str, ref int offset, out JSONValue val)
    {
        val = null;
        int idx = offset;
        char? ch = Util.GetNextNsChar(in_str, ref idx);
        if (null == ch)
        {
            return false;
        }
        else if (ch.Equals('\"'))
        {
            // 字符串
            string str = Util.GetJsonStr(in_str, ref idx);
            if (null != str)
            {
                val = new JSONValue("string", str);
                offset = idx;
                return true;
            }
        }
        else if (char.IsDigit(Convert.ToChar(ch)))
        {
            // 數(shù)字
            string word_str = Util.GetWord(in_str, ref idx);
            int ival;
            if (null != word_str
                && int.TryParse(word_str, out ival))
            {
                val = new JSONValue("number", ival);
                offset = idx;
                return true;
            }
        }
        else if (ch.Equals('{'))
        {
            // JSON對象
            JSONObject obj;
            if (JSONObject.TryParse(in_str, ref idx, out obj))
            {
                val = new JSONValue("JSON Object", obj);
                offset = idx;
                return true;
            }
        }
        else if (ch.Equals('['))
        {
            // JSON數(shù)組
            JSONArray arr;
            if (JSONArray.TryParse(in_str, ref idx, out arr))
            {
                val = new JSONValue("JSON Array", arr);
                offset = idx;
                return true;
            }
        }
        else
        {
            // true,false,null
            string word = Util.GetWord(in_str, ref idx);
            if (word.ToLower().Equals("true"))
            {
                val = new JSONValue("bool", true);
                offset = idx;
                return true;
            }
            else if (word.ToLower().Equals("false"))
            {
                val = new JSONValue("bool", false);
                offset = idx;
                return true;
            }
            else if (word.ToLower().Equals("null"))
            {
                val = new JSONValue("null", null);
                offset = idx;
                return true;
            }
        }
        return false;
    }
}

class Util
{
    public static char? GetNextNsChar(string in_str, ref int offset)
    {
        char? ret = null;
        for (int i = offset; i < in_str.Length; i++)
        {
            if (char.IsWhiteSpace(in_str[i])
                || in_str[i].Equals('\r')
                || in_str[i].Equals('\n'))
            {
            }
            else
            {
                offset = i;
                return in_str[i] as char?;
            }
        }
        return ret;
    }
    public static string GetWord(string in_str, ref int offset)
    {
        StringBuilder sb = new StringBuilder();
        for (int i = offset; i < in_str.Length; i++)
        {
            char ch = in_str[i];
            if (char.IsWhiteSpace(ch)
                || ch.Equals('\r')
                || ch.Equals('\n'))
            {
                if (0 != sb.Length)
                {
                    offset = i - 1;
                    return sb.ToString();
                }
                break;
            }
            else
            {
                sb.Append(ch);
            }
        }
        return null;
    }
    public static string GetJsonStr(string in_str, ref int offset)
    {
        int idx = offset;
        char? quote = GetNextNsChar(in_str, ref idx);
        if (!quote.Equals('"'))
        {
            return null;
        }
        StringBuilder sb = new StringBuilder();
        sb.Append(in_str[idx]);
        for (int i = idx + 1; i < in_str.Length; i++)
        {
            char ch = in_str[i];
            if (ch.Equals('\r') || ch.Equals('\n'))
            {
                // 回車換行
                break;
            }
            else if (ch.Equals('\\'))
            {
                // 轉(zhuǎn)義字符
                sb.Append(ch);
                if (i + 1 < in_str.Length
                    && !in_str[i + 1].Equals('\r')
                    && !in_str[i + 1].Equals('\n'))
                {
                    sb.Append(in_str[i + 1]);
                    i += 1;
                }
                else
                {
                    break;
                }
            }
            else if (ch.Equals('"'))
            {
                // 字符串結(jié)束
                sb.Append(ch);
                offset = i;
                return sb.ToString();
            }
            else
            {
                sb.Append(ch);
            }
        }
        return null;
    }
}

參考:

http://www.json.org.cn/

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末砂沛,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子惠毁,更是在濱河造成了極大的恐慌圾旨,老刑警劉巖季稳,帶你破解...
    沈念sama閱讀 211,348評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡狰住,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評論 2 385
  • 文/潘曉璐 我一進店門齿梁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人勺择,你說我怎么就攤上這事创南。” “怎么了省核?”我有些...
    開封第一講書人閱讀 156,936評論 0 347
  • 文/不壞的土叔 我叫張陵稿辙,是天一觀的道長。 經(jīng)常有香客問我气忠,道長邻储,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,427評論 1 283
  • 正文 為了忘掉前任旧噪,我火速辦了婚禮吨娜,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘淘钟。我一直安慰自己宦赠,他們只是感情好,可當我...
    茶點故事閱讀 65,467評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著勾扭,像睡著了一般缤骨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上尺借,一...
    開封第一講書人閱讀 49,785評論 1 290
  • 那天绊起,我揣著相機與錄音,去河邊找鬼燎斩。 笑死虱歪,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的栅表。 我是一名探鬼主播笋鄙,決...
    沈念sama閱讀 38,931評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼怪瓶!你這毒婦竟也來了萧落?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,696評論 0 266
  • 序言:老撾萬榮一對情侶失蹤洗贰,失蹤者是張志新(化名)和其女友劉穎找岖,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體敛滋,經(jīng)...
    沈念sama閱讀 44,141評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡许布,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,483評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了绎晃。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蜜唾。...
    茶點故事閱讀 38,625評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖庶艾,靈堂內(nèi)的尸體忽然破棺而出袁余,到底是詐尸還是另有隱情,我是刑警寧澤咱揍,帶...
    沈念sama閱讀 34,291評論 4 329
  • 正文 年R本政府宣布颖榜,位于F島的核電站,受9級特大地震影響述召,放射性物質(zhì)發(fā)生泄漏朱转。R本人自食惡果不足惜蟹地,卻給世界環(huán)境...
    茶點故事閱讀 39,892評論 3 312
  • 文/蒙蒙 一积暖、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧怪与,春花似錦夺刑、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽存淫。三九已至,卻和暖如春沼填,著一層夾襖步出監(jiān)牢的瞬間桅咆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工坞笙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留岩饼,地道東北人。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓薛夜,卻偏偏與公主長得像籍茧,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子梯澜,可洞房花燭夜當晚...
    茶點故事閱讀 43,492評論 2 348

推薦閱讀更多精彩內(nèi)容