diff --git a/gjson.go b/gjson.go index 65efa07..58c6cbc 100644 --- a/gjson.go +++ b/gjson.go @@ -1103,6 +1103,7 @@ func parseObject(c *parseContext, i int, path string) (int, bool) { } hit = pmatch && !rp.more for ; i < len(c.json); i++ { + var num bool switch c.json[i] { default: continue @@ -1150,15 +1151,13 @@ func parseObject(c *parseContext, i int, path string) (int, bool) { return i, true } } - case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - i, val = parseNumber(c.json, i) - if hit { - c.value.Raw = val - c.value.Type = Number - c.value.Num, _ = strconv.ParseFloat(val, 64) - return i, true + case 'n': + if i+1 < len(c.json) && c.json[i+1] != 'u' { + num = true + break } - case 't', 'f', 'n': + fallthrough + case 't', 'f': vc := c.json[i] i, val = parseLiteral(c.json, i) if hit { @@ -1171,6 +1170,18 @@ func parseObject(c *parseContext, i int, path string) (int, bool) { } return i, true } + case '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'i', 'I', 'N': + num = true + } + if num { + i, val = parseNumber(c.json, i) + if hit { + c.value.Raw = val + c.value.Type = Number + c.value.Num, _ = strconv.ParseFloat(val, 64) + return i, true + } } break } @@ -1358,6 +1369,7 @@ func parseArray(c *parseContext, i int, path string) (int, bool) { } else { ch = c.json[i] } + var num bool switch ch { default: continue @@ -1440,26 +1452,13 @@ func parseArray(c *parseContext, i int, path string) (int, bool) { return i, true } } - case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - i, val = parseNumber(c.json, i) - if rp.query.on { - var qval Result - qval.Raw = val - qval.Type = Number - qval.Num, _ = strconv.ParseFloat(val, 64) - if procQuery(qval) { - return i, true - } - } else if hit { - if rp.alogok { - break - } - c.value.Raw = val - c.value.Type = Number - c.value.Num, _ = strconv.ParseFloat(val, 64) - return i, true + case 'n': + if i+1 < len(c.json) && c.json[i+1] != 'u' { + num = true + break } - case 't', 'f', 'n': + fallthrough + case 't', 'f': vc := c.json[i] i, val = parseLiteral(c.json, i) if rp.query.on { @@ -1487,6 +1486,9 @@ func parseArray(c *parseContext, i int, path string) (int, bool) { } return i, true } + case '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'i', 'I', 'N': + num = true case ']': if rp.arrch && rp.part == "#" { if rp.alogok { @@ -1562,6 +1564,26 @@ func parseArray(c *parseContext, i int, path string) (int, bool) { } return i + 1, false } + if num { + i, val = parseNumber(c.json, i) + if rp.query.on { + var qval Result + qval.Raw = val + qval.Type = Number + qval.Num, _ = strconv.ParseFloat(val, 64) + if procQuery(qval) { + return i, true + } + } else if hit { + if rp.alogok { + break + } + c.value.Raw = val + c.value.Type = Number + c.value.Num, _ = strconv.ParseFloat(val, 64) + return i, true + } + } break } } @@ -2081,6 +2103,7 @@ func parseAny(json string, i int, hit bool) (int, Result, bool) { if json[i] <= ' ' { continue } + var num bool switch json[i] { case '"': i++ @@ -2100,15 +2123,13 @@ func parseAny(json string, i int, hit bool) (int, Result, bool) { } } return i, res, true - case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - i, val = parseNumber(json, i) - if hit { - res.Raw = val - res.Type = Number - res.Num, _ = strconv.ParseFloat(val, 64) + case 'n': + if i+1 < len(json) && json[i+1] != 'u' { + num = true + break } - return i, res, true - case 't', 'f', 'n': + fallthrough + case 't', 'f': vc := json[i] i, val = parseLiteral(json, i) if hit { @@ -2121,7 +2142,20 @@ func parseAny(json string, i int, hit bool) (int, Result, bool) { } return i, res, true } + case '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'i', 'I', 'N': + num = true } + if num { + i, val = parseNumber(json, i) + if hit { + res.Raw = val + res.Type = Number + res.Num, _ = strconv.ParseFloat(val, 64) + } + return i, res, true + } + } return i, res, false } diff --git a/gjson_test.go b/gjson_test.go index 302126e..39ae212 100644 --- a/gjson_test.go +++ b/gjson_test.go @@ -5,6 +5,7 @@ import ( "encoding/hex" "encoding/json" "fmt" + "math" "math/rand" "strconv" "strings" @@ -2235,3 +2236,32 @@ func TestKeysValuesModifier(t *testing.T) { assert(t, Get(`[]`, `@values`).String() == `[]`) assert(t, Get(`[1,2,3]`, `@values`).String() == `[1,2,3]`) } + +func TestNaNInf(t *testing.T) { + json := `[+Inf,-Inf,Inf,iNF,-iNF,+iNF,NaN,nan,nAn,-0,+0]` + raws := []string{"+Inf", "-Inf", "Inf", "iNF", "-iNF", "+iNF", "NaN", "nan", + "nAn", "-0", "+0"} + nums := []float64{math.Inf(+1), math.Inf(-1), math.Inf(0), math.Inf(0), + math.Inf(-1), math.Inf(+1), math.NaN(), math.NaN(), math.NaN(), + math.Copysign(0, -1), 0} + + // assert(t, int(Get(json, `#`).Int()) == len(raws)) + for i := 0; i < len(raws); i++ { + r := Get(json, fmt.Sprintf("%d", i)) + // fmt.Printf("%s %s\n", r.Raw, raws[i]) + assert(t, r.Raw == raws[i]) + // fmt.Printf("%f %f\n", r.Num, nums[i]) + assert(t, r.Num == nums[i] || (math.IsNaN(r.Num) && math.IsNaN(nums[i]))) + } + // println("------------") + var i int + Parse(json).ForEach(func(_, r Result) bool { + // fmt.Printf("%s %s\n", r.Raw, raws[i]) + assert(t, r.Raw == raws[i]) + // fmt.Printf("%f %f\n", r.Num, nums[i]) + assert(t, r.Num == nums[i] || (math.IsNaN(r.Num) && math.IsNaN(nums[i]))) + i++ + return true + }) + +}