我需要将包含一些 BigDecimal 字段的 Ruby 哈希转换为 JSON。

我需要将 BigDecimal 转换为浮点数/整数,但“json”库总是将其转换为科学记数法。

require 'json'
require 'bigdecimal'

obj = {}
obj['created_at'] = BigDecimal('0.12345')

puts "JSON.dump(obj) = #{JSON.dump(obj)}"
puts "JSON.generate(obj) = #{JSON.generate(obj)}"
puts "JSON.fast_generate(obj) = #{JSON.fast_generate(obj)}"
puts "JSON.pretty_generate(obj) = #{JSON.pretty_generate(obj)}"

结果:
JSON.dump(obj) = {"created_at":"0.12345e0"}
JSON.generate(obj) = {"created_at":"0.12345e0"}
JSON.fast_generate(obj) = {"created_at":"0.12345e0"}
JSON.pretty_generate(obj) = {
  "created_at": "0.12345e0"
}

是否有任何可以指定数字格式的 JSON 库,以便在解析对象时,BigDecimal 字段不会转换为科学记数法?
obj['created_at'] = BigDecimal.new('0.12345')
JSON.parse(obj) = { "created_at": "0.12345" } # not 0.12345e0

我正在使用 ruby​​ 2.4.1p111

最佳答案

JSON 库要求对象具有可用于重建该对象的字符串表示形式。如果很明显它是什么(例如 int 或 float),这些字符串将被解释回这些类型:

> JSON.dump(1234)
=> "1234"
> JSON.dump(1234.456)
=> "1234.456"
> JSON.dump(1.2e22)
=> "1.2e+22"

自动重建:
> JSON.parse(JSON.dump(1234))
=> 1234
> JSON.parse(JSON.dump(1.2e22))
=> 1.2e+22

BigDecimal 使用您看到的特定表示:
> tgt=BigDecimal('0.12345')
=> 0.12345e0
> tgt.inspect
=> "0.12345e0"

虽然这是浮点字符串的合法格式,但如果采用该格式,它不会自动触发 JSON 解码器重建 BigDecimal 或浮点对象:
> JSON.parse(JSON.dump(tgt))
=> "0.12345e0"

您可以在编码为 JSON 之前调用 .to_f(并且可能会失去 BigDecimal 的额外精度):
> JSON.parse(JSON.dump(tgt.to_f))
=> 0.12345

获得自动 float 。

或者,知道什么是 BigDecimal 并在输入时重新编码:
> BigDecimal(JSON.parse(JSON.dump(tgt)))
=> 0.12345e0

或者,您可以使用 BigDecimal 的 format options 转换为字符串浮点表示(不丢失 BigDecimal 内部表示):
> tgt.to_s('F')
=> "0.12345"

但是,同样,当作为 JSON 加载时,您可能会失去 BigDecimal=>BigDecimal.to_s('F')=>float 的准确性,因为解码器会自动将该表示转换为普通浮点数。

关于json - Ruby json 库将 BigDecimal 转换为科学记数法,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/45421201/

10-13 09:23