Лучшее форматирование строк в Scala

С слишком большим количеством аргументов String.format легко становится слишком запутанным. Есть ли более мощный способ форматирования String. Например:

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

Или это невозможно из-за проблем с типом (format нужно взять карту [String, Any], я полагаю, не знаю, будет ли это еще хуже).

Или лучший способ сделать это следующим образом:

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

даже если он загрязняет пространство имен?

Edit:

В то время как простой сутенерство может делать во многих случаях, Im также ищет что-то, идущее в том же направлении, что и Pythons format() (см. http://docs.python.org/release/3.1.2/library/string.html#formatstrings)

Ответ 1

В Scala 2.10 вы можете использовать строчную интерполяцию.

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

Ответ 4

Вы можете легко реализовать более богатое форматирование самостоятельно (с помощью подхода pimp-my-library):

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

Ответ 5

Если вы используете 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 ))

Ответ 6

Это ответ, который я пришел сюда:

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

Ответ 7

Вы также можете рассмотреть использование механизма шаблонов для действительно сложных и длинных строк. Наверху у меня Scalate, который реализует среди других Mustache.

Возможно, вы потеряете избыток и потери производительности для простых строк, но вы, кажется, находитесь в той области, где они начинают становиться реальными шаблонами.