如何美化打印小数格式

ibps3vxo  于 2022-10-15  发布在  Ruby
关注(0)|答案(4)|浏览(157)

当我漂亮地打印小数时,有没有办法更改它们的默认格式?

irb(main):521:0> pp 10.to_d / 2.5   
0.4e1

我想将其格式化为:

irb(main):521:0> pp 10.to_d / 2.5   
4.0

我真的不关心潜在的精确度损失。当您打印精美的Rails记录时,默认格式尤其令人讨厌:

<
  ...  
  id: 49391,  
  operator_id: 1,  
  tax_rate: 0.10e2,  
  sales_price: 0.1e2,  
  unit_price: 0.2e1,  
  >

我知道我可以做to_sto_f等等,但精美印刷的全部意义在于,我不必在快速浏览之前转换我的记录。

mnemlml8

mnemlml81#

你可以对漂亮打印机使用的方法进行简单修补。“普通”IRB使用inspect,但大多数漂亮打印器库都有自己的方法。
例如,标准库中的pp library使用一个名为pretty_print的方法。遗憾的是,BigDecimal没有自己的pretty_print实现,它只是继承了Numeric的实现,而Numeric只是委托给inspect
所以,我们可以写我们自己的!

class BigDecimal
  def pretty_print(pp)
    pp.text to_s('F')
  end
end

pp 10.to_d / 2.5

# 4.0
tv6aics1

tv6aics12#

当您使用to_dto_f时,您是在告诉Ruby将值转换为BigDouble或Float,但这并没有指定输出格式,这是一个不同的问题。
Ruby支持多种类型的字符串格式,但通常需要定义一种格式,然后使用该格式“美化”输出:

foo = 0.4e1
'%1.1f' % foo # => "4.0"

请注意,输出是字符串,而不是浮点数或BigDecimal。在输出到控制台之前,所有内容都被转换为字符串。Ruby的格式字符串遵循C、Perl和许多其他语言使用的sprintf格式字符串。有关更多信息,请参见sprintf
而且,虽然sprintf存在,但我很少看到它被使用。相反,更经常使用的是字符串的%方法,其次是内核的format方法。
另请注意,10.to_d / 2.5无效,因为10是一个整数,而Integer不知道如何计算to_d

10.class # => Integer
10.respond_to?(:to_d) # => false
10.to_d / 2.5    # => NoMethodError: undefined method `to_d' for 10:Integer

需要BigDecimal才能获取to_d

require 'bigdecimal'
require 'bigdecimal/util'

10.to_d / 2.5    # => 0.4e1
rm5edbpk

rm5edbpk3#

在Ruby 2.4中,BigDecimal#inspect等同于BigDecimal#to_sBigDecimal#to_s始终默认使用科学计数法。

decimal = 10.to_d / 2.5
decimal.inspect

# => "0.4e1"

# equivalent to

decimal.to_s

# => "0.4e1"

幸运的是,该类接受to_s方法的参数,该方法允许您指定结果字符串的格式。在其他选项中,您可以指定是使用科学记数法还是传统的浮点记数法。因此,通过按如下方式使用它,您可以获得所需的结果:

decimal.to_s("F")

# => "4.0"

BigDecimal#to_s的文档详细介绍了如何设置进一步的格式选项。
不幸的是,对于您显而易见的用例,在Ruby中无法更改默认格式。为了获得浮点表示法,您总是必须显式地将"F"参数添加到to_s方法。

fcg9iug3

fcg9iug34#

好的,这个问题一直困扰着我,我最终决定做点什么。以下是我的解决方案:

module BigDecimalForIrb
  def inspect
    to_s "F"
  end
end

BigDecimal.send :prepend, BigDecimalForIrb

您可以将其直接添加到.irbrc文件中。或者,如果您将其放在一个单独的文件中,您有两个选择:将其加载到.irbrc中,或者在您想要使用它的时候在控制台中手动加载它。
(请注意,#prepend仅在Ruby 2.0中可用。如果出于某种疯狂的原因,您仍然使用Ruby 1.x,那么您可以使用alias_method_chain来做类似的事情。)

相关问题