2014-11-04 73 views
2

我想在斯卡拉實現一個Scala風格的字符串插值。下面是一個例子,在斯卡拉實現Scala風格的字符串插值

val str = "hello ${var1} world ${var2}" 

在運行時,我想用一些運行時字符串替換「$ {var1}」和「$ {var2}」。然而,欲以Regex.replaceAllIn時(目標:CharSequence中,替代品:(比賽)⇒字符串),我遇到了以下問題:

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正則表達式中的錯誤。如果是這樣,是否還有其他優雅的方式來實現相同的目標(除了殘酷的力量全部替換所有佔位符)?

回答

3

$是替代字符串中特別處理的。這在the documentationreplaceAllIn的描述:

在替換字符串,美元符號($),接着是多個將通過對應於9被解釋爲對在匹配的模式的一組參考,有數字1前九個小組,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" 
+0

是的,這正是問題所在。謝謝。 – 2014-11-04 22:31:51

+0

對於那些對我所做的字符串插值有興趣的人。我有一個地圖,所有佔位符都可以替換。例如, VAL PARAMS =地圖( 「$ {VAR1}」 - > 「富」, 「$ {VAR2}」 - > 「欄」) 然後將下面的作品完美地串插 「」 「(\ $ \ {\ w + \})」「」。r.replaceAllIn(str,m => params.get(m.matched).getOrElse(「」)) – 2014-11-04 22:40:29

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)