duanou2526 2018-11-21 17:09
浏览 650
已采纳

需要将JSON中的整数解析为整数,而不是浮点数

First of all let me explain the problem.

I have a stream of JSON records coming into my Golang app. It basically forwards these to a data store (InfluxDB). There are some integer values in the JSON, and also some float values. It is essential that these get forwarded to the data store with the original data type. If they don't, there will be type conflicts and the write operation will fail.

The Ruby JSON parser has no trouble doing this:

require 'json'
obj = { "a" => 123, "b" => 12.3 }
parsed = JSON.parse(obj.to_json)

print parsed["a"].class # => Integer
print parsed["b"].class # => Float

The encoding/json package in Golang, does have some trouble (all numbers are parsed as floats):

package main

import "encoding/json"
import "fmt"

func main () {
  str := "{\"a\":123,\"b\":12.3}"
  var parsed map[string]interface{}
  json.Unmarshal([]byte(str), &parsed)
  for key, val := range parsed {
    switch val.(type) {
    case int:
      fmt.Println("int type: ", key)
    case float64:
      fmt.Println("float type: ", key)
    default:
      fmt.Println("unknown type: ", key)
    }
  }
}

Which prints:

float type:  a
float type:  b

I need a way to parse ints as ints, and floats as floats, in the way the Ruby JSON parser does.

It is not feasible in this case to parse everything as strings and check whether or not there is a decimal. Certain values come in as strings such as "123" and I need to push those as strings.

I do not have structs for the parsed objects, nor is that an option. The golang app doesn't actually care about the schema and just forwards the input as it receives it.


I tried the approach outlined here: Other ways of verifying reflect.Type for int and float64 (using reflect) but it did not accurately identify the int:

t := reflect.TypeOf(parsed["a"])
k := t.Kind()
k == reflect.Int // false
k == reflect.Float64 // true

展开全部

  • 写回答

2条回答 默认 最新

  • donglianglu8136 2018-11-21 19:43
    关注

    For example, Ruby JSON number types using the general Go mechanism for custom JSON values,

    package main
    
    import (
        "encoding/json"
        "fmt"
        "strconv"
    )
    
    func main() {
        str := `{"a":123,"b":12.3,"c":"123","d":"12.3","e":true}`
        var raw map[string]json.RawMessage
        err := json.Unmarshal([]byte(str), &raw)
        if err != nil {
            panic(err)
        }
        parsed := make(map[string]interface{}, len(raw))
        for key, val := range raw {
            s := string(val)
            i, err := strconv.ParseInt(s, 10, 64)
            if err == nil {
                parsed[key] = i
                continue
            }
            f, err := strconv.ParseFloat(s, 64)
            if err == nil {
                parsed[key] = f
                continue
            }
            var v interface{}
            err = json.Unmarshal(val, &v)
            if err == nil {
                parsed[key] = v
                continue
            }
            parsed[key] = val
        }
        for key, val := range parsed {
            fmt.Printf("%T: %v %v
    ", val, key, val)
        }
    }
    

    Playground: https://play.golang.org/p/VmG8IZV4CG_Y

    Output:

    int64: a 123 
    float64: b 12.3 
    string: c 123 
    string: d 12.3 
    bool: e true 
    

    Another example, Ruby JSON number types using the Go json.Number type,

    package main
    
    import (
        "encoding/json"
        "fmt"
        "strings"
    )
    
    func main() {
        str := `{"a":123,"b":12.3,"c":"123","d":"12.3","e":true}`
        var parsed map[string]interface{}
        d := json.NewDecoder(strings.NewReader(str))
        d.UseNumber()
        err := d.Decode(&parsed)
        if err != nil {
            panic(err)
        }
        for key, val := range parsed {
            n, ok := val.(json.Number)
            if !ok {
                continue
            }
            if i, err := n.Int64(); err == nil {
                parsed[key] = i
                continue
            }
            if f, err := n.Float64(); err == nil {
                parsed[key] = f
                continue
            }
        }
        for key, val := range parsed {
            fmt.Printf("%T: %v %v
    ", val, key, val)
        }
    }
    

    Playground: https://play.golang.org/p/Hk_Wb0EM-aY

    Output:

    int64: a 123
    float64: b 12.3
    string: c 123
    string: d 12.3
    bool: e true
    

    A working version of @ShudiptaSharma's suggestion.

    展开全部

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)
编辑
预览

报告相同问题?

悬赏问题

  • ¥100 有能够实现人机模式的c/c++代码,有图片背景等,能够直接进行游戏
  • ¥20 校园网认证openwrt插件
  • ¥15 以AT89C51单片机芯片为核心来制作一个简易计算器,外部由4*4矩阵键盘和一个LCD1602字符型液晶显示屏构成,内部由一块AT89C51单片机构成,通过软件编程可实现简单加减乘除。
  • ¥15 某东JD算法逆向算法
  • ¥15 求GCMS辅导数据分析
  • ¥30 SD中的一段Unet下采样代码其中的resnet是谁跟谁进行残差连接
  • ¥15 Unet采样阶段的res_samples问题
  • ¥60 Python+pygame坦克大战游戏开发实验报告
  • ¥15 R语言regionNames()和demomap()无法选中中文地区的问题
  • ¥15 Open GL ES 的使用
手机看
程序员都在用的中文IT技术交流社区

程序员都在用的中文IT技术交流社区

专业的中文 IT 技术社区,与千万技术人共成长

专业的中文 IT 技术社区,与千万技术人共成长

关注【CSDN】视频号,行业资讯、技术分享精彩不断,直播好礼送不停!

关注【CSDN】视频号,行业资讯、技术分享精彩不断,直播好礼送不停!

客服 返回
顶部