【问题标题】:Better String formatting in ScalaScala 中更好的字符串格式
【发布时间】:2010-10-29 11:22:31
【问题描述】:

如果参数太多,String.format 很容易变得过于混乱。有没有更强大的方法来格式化字符串。像这样:

"This is #{number} string".format("number" -> 1)

或者这不可能是因为类型问题(我认为format 需要使用 Map[String, Any];不知道这是否会使事情变得更糟)。

或者是这样更好的方法:

val number = 1
<plain>This is { number } string</plain> text

即使它污染了命名空间?

编辑:

虽然在许多情况下可能会进行简单的拉皮条,但我也在寻找与 Python 的 format() 相同方向的东西(参见:http://docs.python.org/release/3.1.2/library/string.html#formatstrings

【问题讨论】:

  • FWIW,我不同意一个人需要处于String.format 有太多参数的情况。使用两个或多个字符串;与+ 连接。但是,如果有人花时间为那些更喜欢这种风格而不是 C 风格的人克隆 python 格式,那当然会很好。
  • 当然,应用程序并不多,但有时您只想将模板字符串外部化,然后我认为优势显而易见。或者对于国际化的东西(虽然我不知道是否即使是 Python 格式也足够强大)。
  • 但是Java不应该已经有了这样的东西吗?
  • @Always-Asking(来自suggested edit):发布此问题时,这些标签可能不存在;不过,添加确实有意义。

标签: string scala formatting string-formatting


【解决方案1】:

在 Scala 2.10 中,您可以使用 string interpolation

val height = 1.9d
val name = "James"
println(f"$name%s is $height%2.2f meters tall")  // James is 1.90 meters tall

【讨论】:

    【解决方案2】:

    好吧,如果你唯一的问题是让参数的顺序更灵活,这很容易做到:

    scala> "%d %d" format (1, 2)
    res0: String = 1 2
    
    scala> "%2$d %1$d" format (1, 2)
    res1: String = 2 1
    

    还有借助地图的正则表达式替换:

    scala> val map = Map("number" -> 1)
    map: scala.collection.immutable.Map[java.lang.String,Int] = Map((number,1))
    
    scala> val getGroup = (_: scala.util.matching.Regex.Match) group 1
    getGroup: (util.matching.Regex.Match) => String = <function1>
    
    scala> val pf = getGroup andThen map.lift andThen (_ map (_.toString))
    pf: (util.matching.Regex.Match) => Option[java.lang.String] = <function1>
    
    scala> val pat = "#\\{([^}]*)\\}".r
    pat: scala.util.matching.Regex = #\{([^}]*)\}
    
    scala> pat replaceSomeIn ("This is #{number} string", pf)
    res43: String = This is 1 string
    

    【讨论】:

      【解决方案3】:

      也许 Scala-Enhanced-Strings-Plugin 可以帮助您。看这里:

      Scala-Enhanced-Strings-Plugin Documentation

      【讨论】:

      • 看起来很有趣。 (包括文档和插件。)但还是有点疯狂(两者都有),因为语法有时不使用任何分隔符......
      • 我在生产中使用它,它很棒!仅当要插值的表达式除了变量名之外还有很多语法时,才需要分隔符。
      • 对于 2.10+ 的用户,一定要查看docs.scala-lang.org/overviews/core/string-interpolation.html 的内置字符串插值。感谢 Andrej 指出这一点。
      【解决方案4】:

      这就是我来这里寻找的答案:

      "This is %s string".format(1)
      

      【讨论】:

        【解决方案5】:

        您可以自己轻松实现更丰富的格式(使用“增强我的库”方法):

        scala> implicit def RichFormatter(string: String) = new {
             |   def richFormat(replacement: Map[String, Any]) =
             |     (string /: replacement) {(res, entry) => res.replaceAll("#\\{%s\\}".format(entry._1), entry._2.toString)}
             | }
        RichFormatter: (string: String)java.lang.Object{def richFormat(replacement: Map[String,Any]): String}
        
        scala> "This is #{number} string" richFormat Map("number" -> 1)
        res43: String = This is 1 string
        

        或者在原始答案之后更新的 Scala 版本:

        implicit class RichFormatter(string: String) {
          def richFormat(replacement: Map[String, Any]): String =
            replacement.foldLeft(string) { (res, entry) =>
              res.replaceAll("#\\{%s\\}".format(entry._1), entry._2.toString)
            }
        }
        

        【讨论】:

        • 没错,我什至可以为此使用%(就像在其他一些语言中一样)。但是,它可能会更强大一些......(可能像 python 的格式。)
        【解决方案6】:

        如果您使用的是 2.10,请使用内置插值。否则,如果您不关心极端性能并且不怕功能性单行,您可以使用折叠 + 几个正则表达式扫描:

        val template = "Hello #{name}!"
        val replacements = Map( "name" -> "Aldo" )
        replacements.foldLeft(template)((s:String, x:(String,String)) => ( "#\\{" + x._1 + "\\}" ).r.replaceAllIn( s, x._2 ))
        

        【讨论】:

          【解决方案7】:

          您也可以考虑使用模板引擎来处理非常复杂和长的字符串。在我的头上,我有Scalate,它实现了Mustache 模板引擎。

          对于简单的字符串来说可能是过度杀伤和性能损失,但您似乎正处于它们开始成为真正模板的那个领域。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2022-12-17
            • 2010-10-31
            • 1970-01-01
            • 2017-11-30
            • 2010-09-19
            • 1970-01-01
            • 2010-11-10
            • 2019-03-04
            相关资源
            最近更新 更多