mirror of https://github.com/tidwall/gjson.git
Ensure Parse handles NaN/Inf and returns correct Index
This commit is contained in:
parent
0b52f9a361
commit
7cadbb5756
70
gjson.go
70
gjson.go
|
@ -426,7 +426,8 @@ end:
|
|||
// use the Valid function first.
|
||||
func Parse(json string) Result {
|
||||
var value Result
|
||||
for i := 0; i < len(json); i++ {
|
||||
i := 0
|
||||
for ; i < len(json); i++ {
|
||||
if json[i] == '{' || json[i] == '[' {
|
||||
value.Type = JSON
|
||||
value.Raw = json[i:] // just take the entire raw
|
||||
|
@ -436,16 +437,20 @@ func Parse(json string) Result {
|
|||
continue
|
||||
}
|
||||
switch json[i] {
|
||||
default:
|
||||
if (json[i] >= '0' && json[i] <= '9') || json[i] == '-' {
|
||||
case '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'i', 'I', 'N':
|
||||
value.Type = Number
|
||||
value.Raw, value.Num = tonum(json[i:])
|
||||
case 'n':
|
||||
if i+1 < len(json) && json[i+1] != 'u' {
|
||||
// nan
|
||||
value.Type = Number
|
||||
value.Raw, value.Num = tonum(json[i:])
|
||||
} else {
|
||||
return Result{}
|
||||
// null
|
||||
value.Type = Null
|
||||
value.Raw = tolit(json[i:])
|
||||
}
|
||||
case 'n':
|
||||
value.Type = Null
|
||||
value.Raw = tolit(json[i:])
|
||||
case 't':
|
||||
value.Type = True
|
||||
value.Raw = tolit(json[i:])
|
||||
|
@ -455,9 +460,14 @@ func Parse(json string) Result {
|
|||
case '"':
|
||||
value.Type = String
|
||||
value.Raw, value.Str = tostr(json[i:])
|
||||
default:
|
||||
return Result{}
|
||||
}
|
||||
break
|
||||
}
|
||||
if value.Exists() {
|
||||
value.Index = i
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
|
@ -531,20 +541,12 @@ func tonum(json string) (raw string, num float64) {
|
|||
return
|
||||
}
|
||||
// could be a '+' or '-'. let's assume so.
|
||||
continue
|
||||
} else if json[i] == ']' || json[i] == '}' {
|
||||
// break on ']' or '}'
|
||||
raw = json[:i]
|
||||
num, _ = strconv.ParseFloat(raw, 64)
|
||||
return
|
||||
}
|
||||
if json[i] < ']' {
|
||||
// probably a valid number
|
||||
continue
|
||||
}
|
||||
if json[i] == 'e' || json[i] == 'E' {
|
||||
// allow for exponential numbers
|
||||
continue
|
||||
}
|
||||
// likely a ']' or '}'
|
||||
raw = json[:i]
|
||||
num, _ = strconv.ParseFloat(raw, 64)
|
||||
return
|
||||
}
|
||||
raw = json
|
||||
num, _ = strconv.ParseFloat(raw, 64)
|
||||
|
@ -2971,3 +2973,31 @@ func stringBytes(s string) []byte {
|
|||
func bytesString(b []byte) string {
|
||||
return *(*string)(unsafe.Pointer(&b))
|
||||
}
|
||||
|
||||
func GetPath(r Result, json string) (string, bool) {
|
||||
if len(r.Raw) == 0 || len(json) == 0 {
|
||||
return "", false
|
||||
}
|
||||
p := uintptr((*(*stringHeader)(unsafe.Pointer(&(r.Raw)))).data)
|
||||
s := uintptr((*(*stringHeader)(unsafe.Pointer(&(json)))).data)
|
||||
e := s + uintptr(len(json))
|
||||
if p < s || p >= e {
|
||||
return "", false
|
||||
}
|
||||
i := int(p - s)
|
||||
_ = i
|
||||
// for ; i >= 0; i-- {
|
||||
// if json[i] <= ' ' {
|
||||
// } else if json[i] == ':' {
|
||||
// // inside of an object, read the key string
|
||||
// } else if json[i] == ',' {
|
||||
// // array-value
|
||||
// } else if json[i] == '[' {
|
||||
// // array-value (end or array)
|
||||
// } else {
|
||||
|
||||
// }
|
||||
// }
|
||||
// return "", false
|
||||
return "", false
|
||||
}
|
||||
|
|
|
@ -717,10 +717,6 @@ var exampleJSON = `{
|
|||
}
|
||||
}`
|
||||
|
||||
func TestNewParse(t *testing.T) {
|
||||
//fmt.Printf("%v\n", parse2(exampleJSON, "widget").String())
|
||||
}
|
||||
|
||||
func TestUnmarshalMap(t *testing.T) {
|
||||
var m1 = Parse(exampleJSON).Value().(map[string]interface{})
|
||||
var m2 map[string]interface{}
|
||||
|
@ -2250,16 +2246,28 @@ func TestNaNInf(t *testing.T) {
|
|||
r := Get(json, fmt.Sprintf("%d", i))
|
||||
assert(t, r.Raw == raws[i])
|
||||
assert(t, r.Num == nums[i] || (math.IsNaN(r.Num) && math.IsNaN(nums[i])))
|
||||
assert(t, r.Type == Number)
|
||||
}
|
||||
|
||||
var i int
|
||||
Parse(json).ForEach(func(_, r Result) bool {
|
||||
assert(t, r.Raw == raws[i])
|
||||
assert(t, r.Num == nums[i] || (math.IsNaN(r.Num) && math.IsNaN(nums[i])))
|
||||
assert(t, r.Type == Number)
|
||||
i++
|
||||
return true
|
||||
})
|
||||
|
||||
// Parse should also return valid numbers
|
||||
assert(t, math.IsNaN(Parse("nan").Float()))
|
||||
assert(t, math.IsNaN(Parse("NaN").Float()))
|
||||
assert(t, math.IsNaN(Parse(" NaN").Float()))
|
||||
assert(t, math.IsInf(Parse("+inf").Float(), +1))
|
||||
assert(t, math.IsInf(Parse("-inf").Float(), -1))
|
||||
assert(t, math.IsInf(Parse("+INF").Float(), +1))
|
||||
assert(t, math.IsInf(Parse("-INF").Float(), -1))
|
||||
assert(t, math.IsInf(Parse(" +INF").Float(), +1))
|
||||
assert(t, math.IsInf(Parse(" -INF").Float(), -1))
|
||||
}
|
||||
|
||||
func TestEmptyValueQuery(t *testing.T) {
|
||||
|
@ -2273,3 +2281,14 @@ func TestEmptyValueQuery(t *testing.T) {
|
|||
`#(!=)#`).Raw ==
|
||||
`["ig","tw","fb","tw","ig","tw"]`)
|
||||
}
|
||||
|
||||
func TestParseIndex(t *testing.T) {
|
||||
assert(t, Parse(`{}`).Index == 0)
|
||||
assert(t, Parse(` {}`).Index == 1)
|
||||
assert(t, Parse(` []`).Index == 1)
|
||||
assert(t, Parse(` true`).Index == 1)
|
||||
assert(t, Parse(` false`).Index == 1)
|
||||
assert(t, Parse(` null`).Index == 1)
|
||||
assert(t, Parse(` +inf`).Index == 1)
|
||||
assert(t, Parse(` -inf`).Index == 1)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue