带有命名值的字符串格式

时间:2014-11-09 03:32:58

标签: string scala

我正在搜索惯用的scala方法来格式化带有命名参数的字符串。我知道String方法格式,但它不允许指定命名参数,只有位置可用。

简单示例:

val bob = "Bob"
val alice = "Alice"
val message = "${b} < ${a} and ${a} > ${b}"
message.format(a = alice, b = bob)

将消息定义为单独的值至关重要,因为我想从资源文件加载它而不直接在代码中指定。有许多类似的问题可以通过名为String Interpolation的新scala功能得到解决。但是这并没有解决我的情况:我不能让编译器完成所有工作,因为资源文件是在运行时加载的。

3 个答案:

答案 0 :(得分:3)

目前尚不清楚“位置参数”是指Formatter使用的通常意义还是“论证索引”。

scala> val bob = "Bob"
bob: String = Bob

scala> val alice = "Alice"
alice: String = Alice

scala> val message = "%2$s likes %1$s and %1$s likes %2$s" format (bob, alice)
message: String = Alice likes Bob and Bob likes Alice

你想:

scala> def f(a: String, b: String) = s"$b likes $a and $a likes $b"
f: (a: String, b: String)String

scala> f(b = bob, a = alice)
res2: String = Bob likes Alice and Alice likes Bob

您可以使用反射工具箱或脚本引擎编译插值。

scala> import scala.tools.reflect._
import scala.tools.reflect._

scala> val tb = reflect.runtime.currentMirror.mkToolBox()
tb: scala.tools.reflect.ToolBox[reflect.runtime.universe.type] = scala.tools.reflect.ToolBoxFactory$ToolBoxImpl@162b3d47

scala> val defs = s"""val a = "$alice" ; val b = "$bob""""
defs: String = val a = "Alice" ; val b = "Bob"

scala> val message = "${b} < ${a} and ${a} > ${b}"
message: String = ${b} < ${a} and ${a} > ${b}

scala> val msg = s"""s"$message""""
msg: String = s"${b} < ${a} and ${a} > ${b}"

scala> tb eval (tb parse s"$defs ; $msg")
res3: Any = Bob < Alice and Alice > Bob

scala> def f(a: String, b: String) = tb eval (tb parse s"""val a = "$a"; val b = "$b"; s"$message"""")
f: (a: String, b: String)Any

scala> f(a = alice, b = bob)
res4: Any = Bob < Alice and Alice > Bob

有点过分了。

但请考虑一下:

https://www.playframework.com/documentation/2.0/ScalaTemplates

答案 1 :(得分:1)

我不知道是否可以使用编译器使用的相同解析器。

但是Regex可以处理你给出的例子。

val values = Map("a" -> "Alice", "b" -> "Bob")
val message = "${b} < ${a} and ${a} > ${b}"

def escapeReplacement(s: String): String = 
  s.replace("\\", "\\\\").replace("$", "\\$")

"\\$\\{([^\\}]*)\\}".r.replaceAllIn(message,
  m => escapeReplacement(values(m.group(1))))

答案 2 :(得分:0)

一种方法可能是有一个替换列表(没有限制变量的数量),然后使用类似的东西:

def substituteVar(s:String,subs:Seq[(String,String)]):String=
  subs.foldLeft(s)((soFar,item) => soFar replaceAll("\\$\\{"+item._1+"}", item._2))

substituteVar(message,Seq(("a",alice),("b",bob)))
res12: String = Bob < Alice and Alice > Bob

也可以延长......