Replace multiple words on string using Map of replacements
Asked Answered
L

3

8

I have a map of replacements

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

I would like to replace all occurrences of each map key in the string with the corresponding value.

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"

I have done

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

but I would like something more functional like a map or fold where the function I apply to the string returns another string without needing a mutable variable that is modified inside the loop.

Livvi answered 13/4, 2017 at 19:48 Comment(0)
T
27

One option: use foldLeft on the Map with str as the initial parameter:

replacements.foldLeft(str)((a, b) => a.replaceAllLiterally(b._1, b._2))
// res8: String = This d is very x and I would love to mxc
Therein answered 13/4, 2017 at 19:53 Comment(2)
The issue with this method is that if one of the replacement words is a sub-string of another word, it replaces that. For example if you a word like "aaaple", it will be "dple". Depends on your application, it might or might not become an issue.Sightly
warning: method replaceAllLiterally in class StringOps is deprecated (since 2.13.2): Use s.replace as an exact replacementWells
W
0

I don't really like this, but it should work:

str.split(" ").toList.map { s => 
  if(replacements.get(s).isDefined) { 
    replacements(s) 
  } else { 
    s  
  } 
}.mkString(" ")
Wildawildcat answered 13/4, 2017 at 20:5 Comment(7)
This won't work if I provide a string without spaces. The example I used was for the sole purpose of illustration and easy understanding of the question.Livvi
I see. Well how would you split words then though?Wildawildcat
There is not splitting. This is a string replacement problem. If the provided string is a single string, it should replace the whole string if this is in the replacement map.Livvi
My "not so beautiful" solution would still work in that case though, won't it?Wildawildcat
My solution works too but that is not the point. Your solution doesn't work if you provide a string without spaces and need to replace substrings.Livvi
@Wildawildcat you can replace your whole if .. else statement with replacements.getOrElse(s, s)Pinery
Gosh this is embarrassing! I've used getOrElse trillions of times and forgot about it now. Thanks Cyrille.Wildawildcat
B
0

You can use regex to do that. Be careful about the order.

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
Baroness answered 23/11, 2023 at 13:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.