Better String formatting in Scala

前端 未结 7 1244
孤独总比滥情好
孤独总比滥情好 2020-12-02 12:03

With too many arguments, String.format easily gets too confusing. Is there a more powerful way to format a String. Like so:

\"This is #{number}          


        
相关标签:
7条回答
  • 2020-12-02 12:27

    This the answer I came here looking for:

    "This is %s string".format(1)
    
    0 讨论(0)
  • 2020-12-02 12:29

    In Scala 2.10 you can use 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
    
    0 讨论(0)
  • 2020-12-02 12:30

    You can easily implement a richer formatting yourself (with pimp-my-library approach):

    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
    
    0 讨论(0)
  • 2020-12-02 12:43

    If you're using 2.10 then go with built-in interpolation. Otherwise, if you don't care about extreme performance and are not afraid of functional one-liners, you can use a fold + several regexp scans:

    val template = "Hello #{name}!"
    val replacements = Map( "name" -> "Aldo" )
    replacements.foldLeft(template)((s:String, x:(String,String)) => ( "#\\{" + x._1 + "\\}" ).r.replaceAllIn( s, x._2 ))
    
    0 讨论(0)
  • 2020-12-02 12:45

    You might also consider the use of a template engine for really complex and long strings. On top of my head I have Scalate which implements amongst others the Mustache template engine.

    Might be overkill and performance loss for simple strings, but you seem to be in that area where they start becoming real templates.

    0 讨论(0)
  • 2020-12-02 12:49

    Well, if your only problem is making the order of the parameters more flexible, this can be easily done:

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

    And there's also regex replacement with the help of a map:

    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
    
    0 讨论(0)
提交回复
热议问题