我正在搜索惯用的scala方法来格式化带有命名参数的字符串。我知道String方法格式,但它不允许指定命名参数,只有位置可用。
简单示例:
val bob = "Bob"
val alice = "Alice"
val message = "${b} < ${a} and ${a} > ${b}"
message.format(a = alice, b = bob)
将消息定义为单独的值至关重要,因为我想从资源文件加载它而不直接在代码中指定。有许多类似的问题可以通过名为String Interpolation的新scala功能得到解决。但是这并没有解决我的情况:我不能让编译器完成所有工作,因为资源文件是在运行时加载的。
答案 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
也可以延长......