【问题标题】:Ruby json library convert BigDecimal to scientific notationRuby json 库将 BigDecimal 转换为科学计数法
【发布时间】:2017-07-31 16:40:32
【问题描述】:

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

我需要将 BigDecimal 转换为 Float/Integer,但“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

【问题讨论】:

  • 当您执行a=BigDecimal('0.12345')a.to_f 之类的操作时会发生什么
  • 我知道,但我想知道的是如何让 JSON.parse(a) = 0.12345
  • 更新了我的答案
  • 您要解决什么问题? 0.123450.12345e0 都是 valid JSON numbers 代表完全相同的值,任何标准 JSON 解析器都会正确地将它们解析为相同的值。您是否在某处遇到错误? 为什么您需要不同格式的号码?

标签: json ruby


【解决方案1】:
BigDecimal('0.12345').to_f

应该会给你想要的结果。

更新:

JSON.parse(BigDecimal('0.12345').to_s) # => 0.12345

JSON.parse(BigDecimal('0.12345').to_s).to_s # => "0.12345"

【讨论】:

  • 谢谢。我想在调用 JSON.parse 之前将 BigDecimal 转换为正确的格式是唯一的方法。
【解决方案2】:

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

获得自动浮动。

或者,知道什么是 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 失去准确性,因为解码器会自动将该表示转换为正常的浮点数。

【讨论】:

  • 我明白了,谢谢。我想我必须先转换 BigDecimal 而不是依赖 JSON.parse 函数。
  • 您可能会认为普通浮点数或普通整数具有极高的准确性,并将其与 JSON 一起使用。除非您有特定的理由使用 BigDecimal,否则这种方式会更容易。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-06-22
  • 1970-01-01
  • 2019-07-09
  • 1970-01-01
  • 2015-12-27
  • 1970-01-01
  • 2013-04-07
相关资源
最近更新 更多