json - 如何在 Go 中解析普通和引用的 JSON 数字?

标签 json go

我正在处理第三方基于 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
}

The Go Playground

有解决办法吗?

最佳答案

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

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
}

The Go Playground

请根据您的需要随意调整 UnmarshalJSON,我的间距非常严格。归功于Dave C , 这在很大程度上受到了 his comment on another question 的启发(在上面的解决方案中也有 more variations)。

或者,您可以使用正则表达式预处理 JSON 数据,但如果上述解决方案可行,请不要这样做,这样会快得多。

re := regexp.MustCompile(`(":\s*)([\d\.]+)(\s*[,}])`)
rawJsonByteArray = re.ReplaceAll(rawJsonByteArray, []byte(`$1"$2"$3`))

关于json - 如何在 Go 中解析普通和引用的 JSON 数字?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31625511/

相关文章:

xml - 正确的结构布局以在 go 中解析 xml

jquery - 在 jquery 中访问 xhr 的 json 响应

java - 使用 Hibernate 将 json 值插入到 postgresql 表中

go - 如何从 golang 中的 gzip 或纯文本阅读器读取?

go - 在 go 中使用静态类型构造函数有什么明显的缺点吗?

tensorflow - 在 go 中使用 tensorflow hub

json - 如何检查名称是否已经存在? Azure 资源管理器模板

java - 将 json 映射到 Java 对象

jquery - 从 php 脚本中检索 jquery 中的 JSON

go - 如何从 WaitGroup 调用的函数中捕获运行时错误?