tidwall / gjson

Get JSON values quickly - JSON parser for Go
MIT License
14.1k stars 846 forks source link

Failed to parse inf #242

Closed yuzhichang closed 2 years ago

yuzhichang commented 2 years ago
import (
    "fmt"

    "github.com/tidwall/gjson"
)

func main() {
    js := `{"float_1": -inf, "float_2": +inf}`
    for _, key := range []string{"float_1", "float_2"} {
        r := gjson.Get(js, key)
        fmt.Printf("%v: %+v\n", key, r.String())
    }
}

The following output is not expected:

float_1: -Inf
float_2: 

Version: github.com/tidwall/gjson v1.9.4

tidwall commented 2 years ago

I don't think -Inf is a valid json value.

yuzhichang commented 2 years ago
package main

import (
    "fmt"
    "strconv"

    "github.com/tidwall/gjson"
    "github.com/valyala/fastjson"
)

func main() {
    js := `{"float_1": -inf, "float_2": +inf}`
    fmt.Printf("******tesing gjson******\n")
    for _, key := range []string{"float_1", "float_2"} {
        r := gjson.Get(js, key)
        fmt.Printf("%v: %+v\n", key, r.String())
    }

    fmt.Printf("******tesing fastjson******\n")
    var fjp fastjson.Parser
    var fjv *fastjson.Value
    fjv, _ = fjp.ParseBytes([]byte(js))
    for _, key := range []string{"float_1", "float_2"} {
        r := fjv.GetFloat64(key)
        fmt.Printf("%v: %+v\n", key, r)
    }

    fmt.Printf("******tesing std******\n")
    for _, s := range []string{"-inf", "+inf"} {
        f, _ := strconv.ParseFloat(s, 64)
        fmt.Printf("%s is parsed as: %+v\n", s, f)
    }
}
$ go run poc_gjson.go 
******tesing gjson******
float_1: -Inf
float_2: 
******tesing fastjson******
float_1: -Inf
float_2: +Inf
******tesing std******
-inf is parsed as: -Inf
+inf is parsed as: +Inf

Both fastjson and std work. It's better to follow them.

tidwall commented 2 years ago

I'll consider adding it as I recently added the support to https://github.com/tidwall/pretty/issues/12.

But just to be clear Inf is not valid json, and not allowed by the std Go encoding/json library. It doesn't work in https://jsonlint.com. And it doesn't parse in JS JSON.parse('{"float_1": -inf, "float_2": +inf}').

While you show it parsing with strconv, this fails:

import "encoding/json"

println(json.Valid([]byte(`{"float_1": -inf, "float_2": +inf}`)))

// output: 
// false

var f float64
err := json.Unmarshal([]byte(`{"float_1": -inf, "float_2": +inf}`), &f)
println(err.Error()) 

// output: 
// invalid character 'i' in numeric literal

That being said I do see value in having in the library.

tidwall commented 2 years ago

I added support for Inf and NaN.