@Test
public void testSomething() {
String str = "Hello ${myKey1}, welcome to Stack Overflow. Have a nice ${myKey2}";
Map<String, String> map = new HashMap<String, String>();
map.put("myKey1", "DD84");
map.put("myKey2", "day");
for (Map.Entry<String, String> entry : map.entrySet()) {
str = str.replace("${" + entry.getKey() + "}", entry.getValue());
}
System.out.println(str);
}
Output:
Hello DD84, welcome to Stack Overflow. Have a nice day
For something more complex I'd rather use OGNL.
Answer from Alfredo Osorio on Stack Overflow@Test
public void testSomething() {
String str = "Hello ${myKey1}, welcome to Stack Overflow. Have a nice ${myKey2}";
Map<String, String> map = new HashMap<String, String>();
map.put("myKey1", "DD84");
map.put("myKey2", "day");
for (Map.Entry<String, String> entry : map.entrySet()) {
str = str.replace("${" + entry.getKey() + "}", entry.getValue());
}
System.out.println(str);
}
Output:
Hello DD84, welcome to Stack Overflow. Have a nice day
For something more complex I'd rather use OGNL.
Java 8 reveals a functional approach which is given in this post.
You are just creating a new function for each word in your map and chain them together.
e.g:
public static void main(String[] args) {
Map<String, String> dictionary = new HashMap<>();
String stringToTranslate = "key1 key2"
dictionary.put("key1", "value1");
dictionary.put("key2", "value2");
String translation = dictionary.entrySet().stream()
.map(entryToReplace -> (Function<String, String>) s -> s.replace(entryToReplace.getKey(),
s.replace(entryToReplace.getValue())
.reduce(Function.identity(), Function::andThen)
.apply(stringToTranslate);
}
regex - Java Map replaceAll with multiple String matches - Stack Overflow
java - Replace string in Map key with string from Map value - Stack Overflow
Replace all strings in a List that match keys in a Map
Replace String values with value in Hash Map in Java - Stack Overflow
I'd do it thus:
replace(str, map)
if we have the empty string, the result is the empty string.
if the string starts with one of the keys from the map:
the result is the replacement associated with that key + replace(str', map)
where str' is the substring of str after the key
otherwise the result is the first character of str + replace(str', map)
where str' is the substring of str without the first character
Note that, though formulated recursively, it can (and should, due to Javas notorious small stack space) be implemented as a loop and write the first part of the result (i.e. the replacement string or the first character) to a stringbuilder.
If you have a key in the map that is a prefix of some other key (i.e. "key", "keys") you may need to try the keys in decreasing length.
Note further, that a faster algorithm could be devised that uses Tries instead of HasMaps. This would also be a remedy for the ambiguous key problem.
Here is an outline (not tested):
public static String replace(String it, Map<String, String> map) {
StringBuilder sb = new StringBuilder();
List<String> keys = map.keySet(); // TODO: sort by decreasing length!!
next: while (it.length() > 0) {
for (String k : keys) {
if (it.startsWith(k)) {
// we have a match!
sb.append(map.get(k));
it = it.substring(k.length(), it.length());
continue next;
}
}
// no match, advance one character
sb.append(it.charAt(0));
it = it.substring(1, it.length());
}
return sb.toString();
}
My approach would be the following. There are probably faster solutions, but you can take it a step further if you like the idea.
public String mapReplaceAll5(String str, Map<String, String> replacements) {
Map<String, String> origToMarker = new HashMap<String, String>();
Map<String, String> markerToRepl = new HashMap<String, String>();
char c = 32000;
for(Entry<String, String> e : replacements.entrySet()) {
origToMarker.put(e.getKey(), String.valueOf(c));
markerToRepl.put(String.valueOf(c--), e.getValue());
}
for (Map.Entry<String, String> entry : origToMarker.entrySet()) {
str = str.replaceAll(entry.getKey(), entry.getValue());
}
for (Map.Entry<String, String> entry : markerToRepl.entrySet()) {
str = str.replaceAll(entry.getKey(), entry.getValue());
}
return str;
}
I apparently suck at Googling, lol, because I can't find this. I have a Map<String, String> of nicknames. So it will have like "William", "Will" and "James", "Jim" etc. Problem is, I need to examine a List<String> and swap out any that match but it could be any case. I was hoping there is a way to do some fancy stream type of thing, because what I'm doing now works but it doesn't feel very efficient:
for (Map.Entry<String, String> nick : nicks.entrySet()) {
if (!segments.stream().anyMatch(nick.getKey()::equalsIgnoreCase)) continue;
for (int x=0; x<segments.size(); x++) {
if (!segments.get(x).equalsIgnoreCase(nick.getKey())) continue;
segments.set(x, nick.getValue());
}
}I read about how to easily check the List to see if any strings exist in it, so I can at least avoid having to iterate each element of the list to check for that but I was hoping there was some fancy way to also pull off the replace w/o having to iterate...?