Reputation: 67
I have strings like -
and I also have Map
Map <String, String> wordToDigit = new HashMap<>;
Map.put("two", 2);
Map.put("three", 3);
Map.put("four", 4);
Map.put("five", 5);
Map.put("six", 6);
Map.put("eight",8);
I need to replace the words in a string with the corresponding value in the map. As each string does not contain all the keys, stored in a map. So, How can I do it more efficiently by iterating over the attribute which is the part of the string and not iterate over whole map?
In output :-
1. yes, I have 2, 3, 4 numbers.
2. I have 5, 6, 7 alphabets.
3. 8, 2, 5 are my lucky numbers.
Upvotes: 1
Views: 105
Reputation: 79035
Given below are two different implementations: (1) Using Map
(2) Using List
and array:
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
public static void main(String[] args) throws IOException {
// Test
String[] sentences = { "yes, I have two, three, four numbers.", "I have five, six, seven alphabets.",
"eight, two, five are my lucky numbers.", "Someone gave him FIVE canines and asked him to feed two." };
System.out.println("Using Map: ");
for (String sentence : sentences) {
System.out.println(replaceWordsWithValue1(sentence));
}
System.out.println("Using List and array: ");
for (String sentence : sentences) {
System.out.println(replaceWordsWithValue2(sentence));
}
}
static String replaceWordsWithValue1(String str) {
Map<String, String> wordToDigit = Map.of("two", "2", "three", "3", "four", "4", "five", "5", "six", "6",
"seven", "7", "eight", "8", "nine", "9");
for (String key : wordToDigit.keySet()) {
Pattern pattern = Pattern.compile("\\b" + Pattern.quote(key) + "\\b", Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(str);
while (matcher.find()) {
str = str.replaceAll(matcher.group(), wordToDigit.get(key));
}
}
return str;
}
static String replaceWordsWithValue2(String str) {
String[] values = { "2", "3", "4", "5", "6", "7", "8", "9" };
List<String> keys = List.of("two", "three", "four", "five", "six", "seven", "eight", "nine");
for (String key : keys) {
Pattern pattern = Pattern.compile("\\b" + Pattern.quote(key) + "\\b", Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(str);
while (matcher.find()) {
str = str.replaceAll(matcher.group(), values[keys.indexOf(key)]);
}
}
return str;
}
}
Output:
Using Map:
yes, I have 2, 3, 4 numbers.
I have 5, 6, 7 alphabets.
8, 2, 5 are my lucky numbers.
Someone gave him 5 canines and asked him to feed 2.
Using List and array:
yes, I have 2, 3, 4 numbers.
I have 5, 6, 7 alphabets.
8, 2, 5 are my lucky numbers.
Someone gave him 5 canines and asked him to feed 2.
The logic in both the implementations is straightforward.
Upvotes: 1
Reputation: 5455
I would split the sentence up into words and then rebuild the sentence, using your map to check if each word has a numeric version, and if it does using that in place of the word.
The trick is to add the delimiters back in, as these aren't included by the standard String.split
method.
Map <String, Integer> wordToDigit = new HashMap<>();
wordToDigit.put("two", 2);
wordToDigit.put("three", 3);
wordToDigit.put("four", 4);
wordToDigit.put("five", 5);
wordToDigit.put("six", 6);
wordToDigit.put("eight",8);
String sentence = "yes, I have two, three, four numbers";
String[] words = sentence.split("[^a-zA-Z]+", -1);
int pos = 0;
StringBuilder sb = new StringBuilder();
for(String word : words)
{
int idx = sentence.indexOf(word, pos);
String delim = sentence.substring(pos, idx);
sb.append(delim);
Integer n = wordToDigit.get(word.toLowerCase());
sb.append(n == null ? word : n);
pos += delim.length() + word.length();
}
sb.append(sentence.substring(pos, sentence.length()));
System.out.println(sb);
Output:
yes, I have 2, 3, 4 numbers
and for the other 2 sentences
I have 5, 6, seven alphabets
8, 2, 5 are my lucky numbers.
Upvotes: 1