猿问

如何在 Go 中解析普通和带引号的 JSON 数字?

我正在处理第三方基于 JSON 的 API。通常它将所有数字括在引号中,但有时不会。我对此无能为力。


我正在尝试提出一个解决方案,无论它们是否被引用,它都会解析数字。标准库提供了一个,string字段标签,它允许将数字字段映射到加引号的值,但不幸的是,如果它不在引号中,它就无法处理该值。


func test(s string) {

  err := json.Unmarshal([]byte(s), &struct {

    F1 float64

    F2 float64 `json:",string"`

  }{})

  if err != nil {

    fmt.Println(err)

    return

  }


  fmt.Println("success")

}


func main() {

  test(`{"f1": 1.23}`)   // success

  test(`{"f1": "1.23"}`) // cannot unmarshal string into Go value of type float64

  test(`{"f2": 1.23}`)   // invalid use of ,string struct tag, trying to unmarshal unquoted value into ...

  test(`{"f2": "1.23"}`) // success

}


有没有解决的办法?


梦里花落0921
浏览 310回答 1
1回答

翻阅古今

正确的解决方案是“克隆” float64MarshalJSON并UnmarshalJSON为其定义自定义:type jsonFloat64 float64func (f jsonFloat64) MarshalJSON() ([]byte, error) {  return json.Marshal(float64(f))}func (f *jsonFloat64) UnmarshalJSON(data []byte) error {  if len(data) >= 2 && data[0] == '"' && data[len(data)-1] == '"' {    data = data[1 : len(data)-1]  }  var tmp float64  err := json.Unmarshal(data, &tmp)  if err != nil {    return err  }  *f = jsonFloat64(tmp)  return nil}然后你就可以做这样的事情:func test(s string) {  err := json.Unmarshal([]byte(s), &struct {    F jsonFloat64  }{})  if err != nil {    fmt.Println(err)    return  }  fmt.Println("success")}func main() {  test(`{"f": 1.23}`)   // success  test(`{"f": "1.23"}`) // success}围棋游乐场随意调整UnmarshalJSON您的需求,我的对间距非常严格。归功于Dave C,这受到了他对另一个问题的评论的极大启发(该问题还具有上述解决方案的更多变化)。或者,您可以使用正则表达式预处理 JSON 数据,但如果上述解决方案是可行的选择,则不要这样做,它会快得多。re := regexp.MustCompile(`(":\s*)([\d\.]+)(\s*[,}])`)rawJsonByteArray = re.ReplaceAll(rawJsonByteArray, []byte(`$1"$2"$3`))
随时随地看视频慕课网APP

相关分类

Go
我要回答