为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
梦里花落0921 2021-10-25 16:52:47
我正在处理第三方基于 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}有没有解决的办法?
查看完整描述

1 回答

?
翻阅古今

TA贡献1780条经验 获得超5个赞

正确的解决方案是“克隆” float64MarshalJSON并UnmarshalJSON为其定义自定义:


type jsonFloat64 float64


func (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`))


查看完整回答
反对 回复 2021-10-25
  • 1 回答
  • 0 关注
  • 303 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信