我想在Scala中实现Scala样式的字符串插值。这是一个例子,
val str = "hello ${var1} world ${var2}"
在运行时,我想用一些运行时字符串替换“$ {var1}”和“$ {var2}”。但是,当尝试使用Regex.replaceAllIn(目标:CharSequence,replacer :(匹配)⇒字符串)时,我遇到了以下问题:
import scala.util.matching.Regex
val placeholder = new Regex("""(\$\{\w+\})""")
placeholder.replaceAllIn(str, m => s"A${m.matched}B")
java.lang.IllegalArgumentException: No group with name {var1}
at java.util.regex.Matcher.appendReplacement(Matcher.java:800)
at scala.util.matching.Regex$Replacement$class.replace(Regex.scala:722)
at scala.util.matching.Regex$MatchIterator$$anon$1.replace(Regex.scala:700)
at scala.util.matching.Regex$$anonfun$replaceAllIn$1.apply(Regex.scala:410)
at scala.util.matching.Regex$$anonfun$replaceAllIn$1.apply(Regex.scala:410)
at scala.collection.Iterator$class.foreach(Iterator.scala:743)
at scala.collection.AbstractIterator.foreach(Iterator.scala:1174)
at scala.util.matching.Regex.replaceAllIn(Regex.scala:410)
... 32 elided
然而,当我从正则表达式中删除'$'时,它起作用了:
val placeholder = new Regex("""(\{\w+\})""")
placeholder.replaceAllIn(str, m => s"A${m.matched}B")
res2: String = hello $A{var1}B world $A{var2}B
所以我的问题是,这是否是Scala Regex中的错误。如果是这样,是否有其他优雅的方法来实现相同的目标(除了残酷的力量替换所有占位符的AllLiterally)?
答案 0 :(得分:3)
$
是替换字符串中特别处理的。 replaceAllIn
的{{3}}中描述了这一点:
在替换字符串中,后跟数字的美元符号($)将被解释为对匹配模式中的组的引用,数字1到9对应于前九个组,0表示整个比赛。任何其他字符都是错误的。反斜杠(
\
)字符将被解释为转义字符,可用于转义美元符号。使用Regex.quoteReplacement来转义这些字符。
(实际上,这并没有提到命名组引用,所以我猜它只记录类。)
无论如何,这里要说的是,如果您不希望将它们视为引用,则需要转义替换字符串中的$
个字符。
new scala.util.matching.Regex("""(\$\{\w+\})""")
.replaceAllIn("hello ${var1} world ${var2}", m => s"A\\${m.matched}B")
// "hello A${var1}B world A${var2}B"
答案 1 :(得分:0)
很难说出你对这种行为的期望。问题是s"${m.matched}"
正在转变为"${var1}"
(和"${var2}"
)。 '$'是一个特殊字符,可以说“将名称为{var1}的组放在此处”。
例如:
scala> placeholder.replaceAllIn(str, m => "$1")
res0: String = hello ${var1} world ${var2}
它将匹配替换为第一个捕获组(m
本身)。
很难准确地说出你在做什么,但你可以逃避任何这样的$:
scala> placeholder.replaceAllIn(str, m => s"${m.matched.replace("$","\\$")}")
res1: String = hello ${var1} world ${var2}
如果您真正想要做的是为方法的局部范围内的某些变量评估var1 / var2;那是不可能的。实际上,s"Hello, $name"
模式实际上在编译时转换为new StringContext("Hello, ", "").s(name)
。