擼一個JSON解析器

來源:https://gyl-coder.top/JSONParser/


JSON

JSON(JavaScript Object Notation, JS 對象簡譜) 是一種輕量級的數(shù)據(jù)交換格式。易于人閱讀和編寫癞谒。同時也易于機(jī)器解析和生成底燎。采用完全獨立于語言的文本格式,但是也使用了類似于C語言家族的習(xí)慣(包括C, C++, C#, Java, JavaScript, Perl, Python等)弹砚。這些特性使JSON成為理想的數(shù)據(jù)交換語言双仍。

JSON與JS的區(qū)別以及和XML的區(qū)別具體請參考百度百科:

https://baike.baidu.com/item/JSON/2462549?fr=aladdin

JSON有兩種結(jié)構(gòu):

第一種:對象

“名稱/值”對的集合不同的語言中,它被理解為對象(object)桌吃,紀(jì)錄(record)朱沃,結(jié)構(gòu)(struct),字典(dictionary)茅诱,哈希表(hash table)逗物,有鍵列表(keyed list),或者關(guān)聯(lián)數(shù)組 (associative array)瑟俭。

對象是一個無序的“‘名稱/值’對”集合翎卓。一個對象以“{”(左括號)開始,“}”(右括號)結(jié)束尔当。每個“名稱”后跟一個“:”(冒號)莲祸;“‘名稱/值’ 對”之間使用“,”(逗號)分隔蹂安。

{"姓名": "張三", "年齡": "18"}

第二種:數(shù)組

值的有序列表(An ordered list of values)。在大部分語言中锐帜,它被理解為數(shù)組(array)田盈。

數(shù)組是值(value)的有序集合。一個數(shù)組以“[”(左中括號)開始缴阎,“]”(右中括號)結(jié)束允瞧。值之間使用“,”(逗號)分隔。

值(value)可以是雙引號括起來的字符串(string)蛮拔、數(shù)值(number)述暂、true、false建炫、 null畦韭、對象(object)或者數(shù)組(array)。這些結(jié)構(gòu)可以嵌套肛跌。

通過上面的了解可以看出艺配,JSON存在以下幾種數(shù)據(jù)類型(以Java做類比):

解析JSON

JSON解析器的基本原理

輸入一串JSON字符串,輸出一個JSON對象衍慎。

步驟

JSON解析的過程主要分以下兩步:

第一步:對于輸入的一串JSON字符串我們需要將其解析成一組token流转唉。

例如 JSON字符串{“姓名”: “張三”, “年齡”: “18”} 我們需要將它解析成

{、 姓名稳捆、 :赠法、 張三、 ,乔夯、 年齡砖织、 :、 18末荐、 }

這樣一組token流

第二步:根據(jù)得到的token流將其解析成對應(yīng)的JSON對象(JSONObject)或者JSON數(shù)組(JSONArray)

下面我們來詳細(xì)分析下這兩個步驟:

獲取token流

根據(jù)JSON格式的定義镶苞,token可以分為以下幾種類型

根據(jù)以上的JSON類型,我們可以將其封裝成enum類型的TokenType

在TokenType中我們?yōu)槊恳环N類型都賦一個數(shù)字鞠评,目的是在Parser做一些優(yōu)化操作(通過位運算來判斷是否是期望出現(xiàn)的類型)

在進(jìn)行第一步之前JSON串對計算機(jī)來說只是一串沒有意義的字符而已。第一步的作用就是把這些無意義的字符串變成一個一個的token壕鹉,上面我們已經(jīng)為每一種token定義了相應(yīng)的類型和值剃幌。所以計算機(jī)能夠區(qū)分不同的token,并能以token為單位解讀JSON數(shù)據(jù)晾浴。

下面我們封裝一個token類來存儲每一個token對應(yīng)的值

在解析的過程中我們通過字符流來不斷的讀取字符负乡,并且需要經(jīng)常根據(jù)相應(yīng)的字符來判斷狀態(tài)的跳轉(zhuǎn)。所以我們需要自己封裝一個ReaderChar類脊凰,以便我們更好的操作字符流抖棘。

另外我們還需要一個TokenList來存儲解析出來的token流

JSON解析比其他文本解析要簡單的地方在于茂腥,我們只需要根據(jù)下一個字符就可知道接下來它所期望讀取的到的內(nèi)容是什么樣的。如果滿足期望了切省,則返回 Token最岗,否則返回錯誤。

為了方便程序出錯時更好的debug朝捆,程序中自定義了兩個exception類來處理錯誤信息般渡。(具體實現(xiàn)參考exception包)

下面就是第一步中的重頭戲(核心代碼):

在start方法中,我們將每個處理方法都封裝成了單獨的函數(shù)芙盘。主要思想就是通過一個死循環(huán)不停的讀取字符驯用,然后再根據(jù)字符的期待值,執(zhí)行不同的處理函數(shù)儒老。

下面我們詳解分析幾個處理函數(shù):

該方法也是通過一個死循環(huán)來讀取字符蝴乔,首先判斷的是JSON中的轉(zhuǎn)義字符。

JSON中允許出現(xiàn)的有以下幾種

"

\

\u four-hex-digits

/

具體的處理方法封裝在了isEscape()方法中驮樊,處理Unicode 編碼時要特別注意一下u的后面會出現(xiàn)四位十六進(jìn)制數(shù)薇正。當(dāng)讀取到一個雙引號或者讀取到了非法字符(’ ’或’、’ ’)循環(huán)退出巩剖。

判斷數(shù)字的時候也要特別小心铝穷,注意負(fù)數(shù),frac佳魔,exp等等情況曙聂。

通過上面的解析,我們可以得到一組token鞠鲜,接下來我們需要以這組token作為輸入宁脊,解析出相應(yīng)的JSON對象

解析出JSON對象

解析之前我們需要定義出JSON對象(JSONObject)和JSON數(shù)組(JSONArray)的實體類。

之后我們就可以寫解析類了贤姆,由于代碼較長榆苞,這里就不展示了。有興趣的可以去GitHub上下載。實現(xiàn)邏輯比較簡單衡楞,也易于理解歇僧。

解析類中的parse方法首先根據(jù)第一個token的類型選擇調(diào)用parseJsonObject()或者parseJsonArray(),進(jìn)而返回JSON對象或者JSON數(shù)組赊琳。上面的解析方法中利用位運算來判斷字符的期待值既提高了程序的執(zhí)行效率也有助于提高代碼的ke’du’xi

完成之后我們可以寫一個測試類來驗證下我們的解析器的運行情況。我們可以自己定義一組JSON串也可以通過HttpUtil工具類從網(wǎng)上獲取砰碴。最后通過FormatUtil類來規(guī)范我們輸出躏筏。

具體效果如下圖所示:

擴(kuò)展閱讀

Java轉(zhuǎn)JSON串的幾種方式

JSON是什么?它能帶來什么呈枉?它和XML比較趁尼?

推薦幾個IDEA插件埃碱,Java開發(fā)者擼碼利器

最強(qiáng)解析:支付寶系統(tǒng)架構(gòu)內(nèi)部剖析

一個“Hello World”理解JVM運行時數(shù)據(jù)區(qū)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市酥泞,隨后出現(xiàn)的幾起案子砚殿,更是在濱河造成了極大的恐慌,老刑警劉巖婶博,帶你破解...
    沈念sama閱讀 216,919評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瓮具,死亡現(xiàn)場離奇詭異,居然都是意外死亡凡人,警方通過查閱死者的電腦和手機(jī)名党,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來挠轴,“玉大人传睹,你說我怎么就攤上這事“痘蓿” “怎么了欧啤?”我有些...
    開封第一講書人閱讀 163,316評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長启上。 經(jīng)常有香客問我邢隧,道長,這世上最難降的妖魔是什么冈在? 我笑而不...
    開封第一講書人閱讀 58,294評論 1 292
  • 正文 為了忘掉前任倒慧,我火速辦了婚禮,結(jié)果婚禮上包券,老公的妹妹穿的比我還像新娘纫谅。我一直安慰自己,他們只是感情好溅固,可當(dāng)我...
    茶點故事閱讀 67,318評論 6 390
  • 文/花漫 我一把揭開白布付秕。 她就那樣靜靜地躺著,像睡著了一般侍郭。 火紅的嫁衣襯著肌膚如雪询吴。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,245評論 1 299
  • 那天亮元,我揣著相機(jī)與錄音汰寓,去河邊找鬼。 笑死苹粟,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的跃闹。 我是一名探鬼主播嵌削,決...
    沈念sama閱讀 40,120評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼毛好,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了苛秕?” 一聲冷哼從身側(cè)響起肌访,我...
    開封第一講書人閱讀 38,964評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎艇劫,沒想到半個月后吼驶,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,376評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡店煞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,592評論 2 333
  • 正文 我和宋清朗相戀三年蟹演,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片顷蟀。...
    茶點故事閱讀 39,764評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡酒请,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鸣个,到底是詐尸還是另有隱情羞反,我是刑警寧澤,帶...
    沈念sama閱讀 35,460評論 5 344
  • 正文 年R本政府宣布囤萤,位于F島的核電站昼窗,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏涛舍。R本人自食惡果不足惜澄惊,卻給世界環(huán)境...
    茶點故事閱讀 41,070評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望做盅。 院中可真熱鬧缤削,春花似錦、人聲如沸吹榴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽图筹。三九已至帅刀,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間远剩,已是汗流浹背扣溺。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留瓜晤,地道東北人锥余。 一個月前我還...
    沈念sama閱讀 47,819評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像痢掠,于是被迫代替她去往敵國和親驱犹。 傳聞我的和親對象是個殘疾皇子嘲恍,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,665評論 2 354

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