使用替换映射在字符串中替换多个单词

8

我有一个替换映射表

val replacements = Map("aaa" -> "d", "bbb" -> "x", "ccc" -> "mx")

我想用相应的值替换字符串中所有映射表键的出现。

val str = "This aaa is very bbb and I would love to cccc"
val result = cleanString(str, replacements)
result = "This d is very x and I would love to mx"

我已经完成了

val sb = new StringBuilder(str)
for(repl <- replacements.keySet) yield {
  sb.replaceAllLiterally(repl, replacement.get(repl))
}

但我希望有更多功能的东西,比如像 mapfold 这样的函数,在应用于字符串时返回另一个字符串,而不需要一个在循环内被修改的可变变量。

3个回答

27

一个选项:在 Map 上使用 foldLeft,并将 str 设置为初始参数:

replacements.foldLeft(str)((a, b) => a.replaceAllLiterally(b._1, b._2))
// res8: String = This d is very x and I would love to mxc

1
这种方法的问题在于,如果替换词中有一个是另一个单词的子字符串,它会将其替换掉。例如,如果你有一个单词像“aaaple”,它会变成“dple”。这取决于你的应用程序,可能会成为问题,也可能不会成为问题。 - Mr.Boy
1
warning: method replaceAllLiterally in class StringOps is deprecated (since 2.13.2): Use s.replace as an exact replacement - Amir Shabani

0

我并不是很喜欢这个,但它应该能工作:

str.split(" ").toList.map { s => 
  if(replacements.get(s).isDefined) { 
    replacements(s) 
  } else { 
    s  
  } 
}.mkString(" ")

如果我提供一个没有空格的字符串,这个方法就不会起作用。我使用的例子只是为了说明问题和方便理解。 - locorecto
我明白了。那么你怎么分割单词呢? - mfirry
我的“不太美观”的解决方案在那种情况下仍然有效,对吧? - mfirry
1
@mfirry,你可以用replacements.getOrElse(s, s)来替换整个if .. else语句。 - Cyrille Corpet
天啊,这真是尴尬!我已经使用了无数次的getOrElse,现在居然忘记了。谢谢Cyrille。 - mfirry
显示剩余2条评论

0
你可以使用正则表达式来做这个。注意顺序。
val str = "aaaaaa"
val relaceMap = Map("aaaaa" -> "C", "a" -> "A", "aaa" -> "B")
val pattern = relaceMap.keys.mkString("|").r
val result = pattern.replaceAllIn(str, m => relaceMap(m.matched)) // CA

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接