具有最大位数的字符串格式

时间:2013-06-13 13:59:48

标签: scala string-interpolation

我正在尝试使用最大位数来格式化浮点数,但我不想要不必要的尾随零。我想如果我使用g代替f它会起作用(参见this question

def testF(d: Double) = f"$d%1.2f"
def testG(d: Double) = f"$d%1.2g"

现在这种行为很奇怪:

testF(3.1415)  // --> 3.14 ok
testF(3.1)     // --> 3.10 hmmm, don't want that zero

testG(3.1415)  // --> 3.1 what the ?

好的,也许我需要为g增加一位数字:

def testG(d: Double) = f"$d%1.3g"

testG(3.1415)  // --> 3.14 ok
testG(3.1)     // --> 3.10 grmpf

所以有两个问题 - 一个,为什么h g丢掉一个数字并且似乎并不关心拖尾零?二,我怎么能

testX(3.1415)  // --> 3.14
testX(3.1)     // --> 3.1

3 个答案:

答案 0 :(得分:3)

你可以使用java DecimalFormat,但它可能不会令人满意:

def testX(d: Double) = new java.text.DecimalFormat("#.##").format(d)

还要回答你的第一个问题为什么heck是g丢弃一位并且似乎并不关心尾随零

  

对于浮点转换'e','E'和'f',精度是小数点分隔符后的位数。如果转换为“g”或“G”,那么精确度是舍入后得到的幅度中的总位数

Formatter details

答案 1 :(得分:2)

与C world的printf一样,Java(和Scala)Formatter包括最小和最大字段宽度(对于%s格式说明符):

// Minimum field width -- right-aligned
scala> "%23s".format(23)
res0: String = "                     23"

// Minimum field width -- left-aligned
scala> "%-23s".format(23)
res1: String = "23                     "

// Maximum field width with right truncation
scala> "%.3s".format(12345)
res2: String = 123

// Minimum and maximum width -- right aligned
scala> "%3.3s".format(1)
res3: String = "  1"

// Minimum and maximum width -- left aligned
scala> "%-3.3s".format(1)
res4: String = "1  "

答案 2 :(得分:1)

这个版本怎么样?

使用Formattable需要%s格式,但您可以根据需要使用格式化args进行解释。

Formattable可以在f - 插值中间弹出,因为普通format只使用toString或您的自定义formatTo

package object succinctly {
  import java.util.{ Formattable, FormattableFlags, Formatter }
  import scala.language.implicitConversions
  implicit class Succinctly(val __thing: Double) extends AnyVal {
    @inline def succinctly(s: String): String = s format fmtable(__thing)
    @inline def succinctly: Formattable = fmtable(__thing)
  }
  private[this] val trailing = "(.*\\...*?)(0*)".r
  private[this] def fmtable(a: Double) = new Formattable {
    override def formatTo(formatter: Formatter, flags: Int, width: Int, precision: Int) = formatter.out append (
      if (precision <= 0) a.toInt.toString
      else s"%${width}.${precision}f" format a.asInstanceOf[java.lang.Double] match { case trailing(num, _) => num }
    )
  }
}

package succinctly {
  import scala.language.postfixOps
  import scala.math._
  object Test extends App {
    Console println (Pi succinctly "%1.2s")
    Console println (3.1 succinctly "%1.2s")
    Console println (3.0 succinctly "%1.2s")
    Console println f"${3.1 succinctly}%1.2s"
  }
}

也可以想到编写一个自定义插值器,可以将双打提升为无跟踪,并将%f更改为%s,但需要付出一定代价,因为f - 插值器是一个宏。