Ruby输出数字为2位小数

时间:2016-10-28 06:21:56

标签: json ruby number-formatting

我无法将我的ruby对象序列化为json,更具体地说是数字的格式。 我已经写了一个rspec测试来更准确地说明我的问题。

expected = '{ "foo": 1.00, "bar": 4.50, "abc": 0.00, "xyz": 1.23 }'

it 'serializes as expected' do
  my_hash = { "foo": 1, "bar": 4.5, "abc": 0, "xyz": 1.23}
  expect(my_to_json_method(my_hash)).to eq expected
end 

这是我遇到麻烦的情况。我可以使用sprintf但是如何获得字符串输出,如上例所示?

4 个答案:

答案 0 :(得分:4)

首先,您不应该使用浮点数来表示货币价值。相反,让我们使用更合适的类型:(还有Ruby Money gem)

require 'bigdecimal'

my_hash = {
  foo: BigDecimal.new('1.00'),
  bar: BigDecimal.new('4.50'),
  abc: BigDecimal.new('0.00'),
  xyz: BigDecimal.new('1.23')
}

有几种选择来代表货币价值。根据JSON规范,所有以下JSON字符串都是有效的,并且在解析时都需要特殊处理。您可以选择最合适的。

  

注意:我正在实现一个自定义to_json方法,使用Ruby的默认JSON库将BigDecimal实例转换为JSON。这仅用于演示目的,通常不应修补核心(或stdlib)类。

1。精度固定的数字

这就是你要求的。请注意,默认情况下,许多JSON库会将这些数字解析为浮点值。

class BigDecimal
  def to_json(*)
    '%.2f' % self
  end
end
puts my_hash.to_json

输出:

{"foo":1.00,"bar":4.50,"abc":0.00,"xyz":1.23}

2。数字作为字符串

这将适用于所有JSON库,但将数字存储为字符串对我来说并不合适。

class BigDecimal
  def to_json(*)
    '"%.2f"' % self
  end
end
puts my_hash.to_json

输出:

{"foo":"1.00","bar":"4.50","abc":"0.00","xyz":"1.23"}

3。数字为整数

您只需输出美分作为整数,而不是将货币值表示为小数。这就是我通常做的事情。

class BigDecimal
  def to_json(*)
    (self * 100).to_i.to_s
  end
end
puts my_hash.to_json

输出:

{"foo":100,"bar":450,"abc":0,"xyz":123}

答案 1 :(得分:0)

用户Sprintf

sprintf('%。2f',5.5)

简单地插入您的JSON作为ERB模板。

答案 2 :(得分:0)

您可以使用sprintf,并且可以通过提及%.(number)f获取所需的小数点。

例如:两位小数,%.2f

这是一个真正的实现,

2.2.2 :019 > test = { "foo": (sprintf "%.2f","1.11"), "bar": (sprintf "%.2f","4.55"), "abc": (sprintf "%.2f","0.2") }

 => {:foo=>"1.11", :bar=>"4.55", :abc=>"0.20"}

Here is the reference

答案 3 :(得分:0)

puts '{' << my_hash.map { |k, v| %Q|"#{k}": #{"%.2f" % v}| }.join(', ') << '}'
#⇒ {"foo": 1.00, "bar": 4.50, "abc": 0.00, "xyz": 1.23}