亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.430618.com 】, 免友鏈快審服務(wù)(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

用面向?qū)ο蟮姆绞讲僮?JSON 甚至還能做四則運算 JSON 庫

 

前言

在之前實現(xiàn)的 JSON 解析器中當(dāng)時只實現(xiàn)了將一個 JSON 字符串轉(zhuǎn)換為一個 JSONObject,并沒有將其映射為一個具體的 struct;如果想要獲取值就需要先做斷言將其轉(zhuǎn)換為 map 或者是切片再來獲,會比較麻煩。

 decode, err := gjson.Decode(`{"glossary":{"title":"example glossary","age":1}}`)
 assert.Nil(t, err)
 glossary := v["glossary"].(map[string]interface{})
 assert.Equal(t, glossary["title"], "example glossary")
 assert.Equal(t, glossary["age"], 1)

但其實轉(zhuǎn)念一想,部分場景我們甚至我們只需要拿到 JSON 中的某個字段的值,這樣還需要先聲明一個 struct 會略顯麻煩。

經(jīng)過查詢發(fā)現(xiàn)已經(jīng)有了一個類似的庫來解決該問題,https://github.com/tidwall/gjson 并且 star 數(shù)還很多(甚至名字都是一樣的),說明這樣的需求大家還是很強烈的。

于是我也打算增加類似的功能,使用方式如下:

用面向?qū)ο蟮姆绞讲僮?JSON 甚至還能做四則運算 JSON 庫

 

最后還加上了一個四則運算的功能。

面向?qū)ο蟮姆绞讲僮?JSON

因為功能類似,所以我參考了 tidwall 的 API 但去掉一些我覺得暫時用不上的特性,并調(diào)整了一點語法。

當(dāng)前這個版本只能通過確定的 key 加上 . 點符號訪問數(shù)據(jù),如果是數(shù)組則用 [index] 的方式訪問下標(biāo)。 [] 符號訪問數(shù)組我覺得要更符合直覺一些。

以下是一個包含多重嵌套 JSON 的訪問示例:

str := `
{
"name": "bob",
"age": 20,
"skill": {
    "lang": [
        {
            "go": {
                "feature": [
                    "goroutine",
                    "channel",
                    "simple",
                    true
                ]
            }
        }
    ]
}
}`

name := gjson.Get(str, "name")
assert.Equal(t, name.String(), "bob")

age := gjson.Get(str, "age")
assert.Equal(t, age.Int(), 20)

assert.Equal(t, gjson.Get(str,"skill.lang[0].go.feature[0]").String(), "goroutine")
assert.Equal(t, gjson.Get(str,"skill.lang[0].go.feature[1]").String(), "channel")
assert.Equal(t, gjson.Get(str,"skill.lang[0].go.feature[2]").String(), "simple")
assert.Equal(t, gjson.Get(str,"skill.lang[0].go.feature[3]").Bool(), true)

這樣的語法使用個人覺得還是滿符合直覺的,相信對使用者來說也比較簡單。

返回值參考了 tidwall 使用了一個 Result 對象,它提供了多種方法可以方便的獲取各種類型的數(shù)據(jù)

func (r Result) String() string
func (r Result) Bool() bool
func (r Result) Int() int
func (r Result) Float() float64
func (r Result) Map() map[string]interface{}
func (r Result) Array() *[]interface{}
func (r Result) Exists() bool

比如使用 Map()/Array() 這兩個函數(shù)可以將 JSON 數(shù)據(jù)映射到 map 和切片中,當(dāng)然前提是傳入的語法返回的是一個合法 JSONObject 或數(shù)組。

實現(xiàn)原理

在實現(xiàn)之前需要先定義一個基本語法,主要支持以下四種用法:

  • 單個 key 的查詢:Get(json,"name")
  • 嵌套查詢: Get(json,"obj1.obj2.obj3.name")
  • 數(shù)組查詢:Get(json,"obj.array[0]")
  • 數(shù)組嵌套查詢:Get(json,"obj.array[0].obj2.obj3[1].name")

語法很簡單,符合我們?nèi)粘=佑|到語法規(guī)則,這樣便可以訪問到 JSON 數(shù)據(jù)中的任何一個值。

其實實現(xiàn)過程也不復(fù)雜,我們已經(jīng)在上一文中實現(xiàn)將 JSON 字符串轉(zhuǎn)換為一個 JSONObject 了。

這次只是額外再解析剛才定義的語法為 token,然后解析該 token 的同時再從生成好的 JSONObject 中獲取數(shù)據(jù)。

最后在解析完 token 時拿到的 JSONObject 數(shù)據(jù)返回即可。


用面向?qū)ο蟮姆绞讲僮?JSON 甚至還能做四則運算 JSON 庫

 

我們以這段查詢代碼為例:

首先第一步是對查詢語法做詞法分析,最終得到下圖的 token。

用面向?qū)ο蟮姆绞讲僮?JSON 甚至還能做四則運算 JSON 庫

 

在詞法分析過程中也可以做簡單的語法校驗;比如如果包含數(shù)組查詢,并不是以 ] 符號結(jié)尾時就拋出語法錯誤。

用面向?qū)ο蟮姆绞讲僮?JSON 甚至還能做四則運算 JSON 庫

 

接著我們遍歷語法的 token。如下圖所示:

用面向?qū)ο蟮姆绞讲僮?JSON 甚至還能做四則運算 JSON 庫

 

每當(dāng)遍歷到 token 類型為 Key 時便從當(dāng)前的 JSONObject 對象中獲取數(shù)據(jù),并用獲取到的值替覆蓋為當(dāng)前的 JSONObject。

其中每當(dāng)遇到 . [ ] 這樣的 token 時便消耗掉,直到我們將 token 遍歷完畢,這時將當(dāng)前 JSONObject 返回即可。

在遍歷過程中當(dāng)遇到非法格式時,比如 obj_list[1.] 便會返回一個空的 JSONObject。

語法校驗這點其實也很容易辦到,因為根據(jù)我們的語法規(guī)則,Array 中的 index 后一定緊接的是一個 EndArray,只要不是一個 EndArray 便能知道語法不合法了。

有興趣的可以看下解析過程的源碼:

https://github.com/crossoverJie/gjson/blob/cfbca51cc9bc0c77e6cb9c9ad3f964b2054b3826/json.go#L46

對 JSON 做四則運算

 str := `{"name":"bob", "age":10,"magic":10.1, "score":{"math":[1,2]}}`
 result := GetWithArithmetic(str, "(age+age)*age+magic")
 assert.Equal(t, result.Float(), 210.1)
 result = GetWithArithmetic(str, "(age+age)*age")
 assert.Equal(t, result.Int(), 200)

 result = GetWithArithmetic(str, "(age+age) * age + score.math[0]")
 assert.Equal(t, result.Int(), 201)

 result = GetWithArithmetic(str, "(age+age) * age - score.math[0]")
 assert.Equal(t, result.Int(), 199)

 result = GetWithArithmetic(str, "score.math[1] / score.math[0]")
 assert.Equal(t, result.Int(), 2)

最后我還擴展了一下語法,可以支持對 JSON 數(shù)據(jù)中的整形(int、float)做四則運算,雖然這是一個小眾需求,但做完我覺得還挺有意思的,目前在市面上我還沒發(fā)現(xiàn)有類似功能的庫,可能和小眾需求有關(guān)。

其中核心的四則運算邏輯是由之前寫的腳本解釋器提供的:

https://github.com/crossoverJie/gscript

用面向?qū)ο蟮姆绞讲僮?JSON 甚至還能做四則運算 JSON 庫

 

單獨提供了一個函數(shù),傳入一個四則運算表達(dá)式返回計算結(jié)果。

由于上一版本還不支持 float,所以這次專門適配了一下。

限于篇幅,更多關(guān)于這個四則運算的實現(xiàn)邏輯會在后面繼續(xù)分享。

總結(jié)

至此算是我第一次利用編譯原理的知識解決了一點特定領(lǐng)域問題,在大學(xué)以及工作這些年一直覺得編譯原理比較高深,所以內(nèi)心一直是抗拒的,但經(jīng)過這段時間的學(xué)習(xí)和實踐慢慢的也掌握到了一點門道。

不過目前也只是冰山一角,后面的編譯原理后端更是要涉及到計算機底層知識,所以依然任重而道遠(yuǎn)。

已上都是題外話,針對于這個庫我也會長期維護(hù);為了能達(dá)到生產(chǎn)的使用要求,盡量提高了單測覆蓋率,目前是98%。

也歡迎大家使用,提 bug。

后面會繼續(xù)優(yōu)化,比如支持轉(zhuǎn)義字符、提高性能等。

感興趣的朋友請持續(xù)關(guān)注: https://github.com/crossoverJie/gjson

分享到:
標(biāo)簽:JSON
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運動步數(shù)有氧達(dá)人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定