Reputation:
I am trying to figure out how to go about searching some user input for multiple keywords.The keywords come from a hash map called Synonym. So basically I enter some sentence and if the sentence contains one or more keywords or keyword synonyms I want to call a parse file method. So far I could only search for one keyword. I am stuck trying to get a user input which could be a long sentence or just one word containing the keyword(s) and search the hash map key for that matching word. For example, If the hash map is
responses.put("textbook name", new String[] { "name of textbook", "text", "portfolio" });
responses.put("current assignment", new String[] { "homework","current work" });
and the user inputs " what is the name of textbook that has the homework" I want to search a text file for textbook current assignment. Assuming that the text file contains the sentence The current assignment is in the second textbook name ralphy". I mean i got most of my implementation done, the issue is dealing with more than one keyword. Can someone help me solve this?
Here is my code
private static HashMap<String, String[]> responses = new HashMap<String, String[]>(); // this
public static void parseFile(String s) throws FileNotFoundException {
File file = new File("data.txt");
Scanner scanner = new Scanner(file);
while (scanner.hasNextLine()) {
final String lineFromFile = scanner.nextLine();
if (lineFromFile.contains(s)) {
// a match!
System.out.println(lineFromFile);
// break;
}
}
}
private static HashMap<String, String[]> populateSynonymMap() {
responses.put("test", new String[] { "test load", "quantity of test","amount of test" });
responses.put("textbook name", new String[] { "name of textbook", "text", "portfolio" });
responses.put("professor office", new String[] { "room", "post", "place" });
responses.put("day", new String[] { "time", "date" });
responses.put("current assignment", new String[] { "homework","current work" });
return responses;
}
public static void main(String args[]) throws ParseException, IOException {
/* Initialization */
HashMap<String, String[]> synonymMap = new HashMap<String, String[]>();
synonymMap = populateSynonymMap(); // populate the map
Scanner scanner = new Scanner(System.in);
String input = null;
/*End Initialization*/
System.out.println("Welcome To DataBase ");
System.out.println("What would you like to know?");
System.out.print("> ");
input = scanner.nextLine().toLowerCase();
String[] inputs = input.split(" ");
for (String ing : inputs) { // iterate over each word of the sentence.
boolean found = false;
for (Map.Entry<String, String[]> entry : synonymMap.entrySet()) {
String key = entry.getKey();
String[] value = entry.getValue();
if (input.contains(key) || key.contains(input)|| Arrays.asList(value).contains(input)) {
found = true;
parseFile(entry.getKey());
}
}
}
}
Any help would be appreciated
Upvotes: 0
Views: 4017
Reputation: 4491
You could use a single regex pattern per "dictionary entry" and test each pattern against your input. Depending on your performance requirements and the size of your dictionary and input, it might be a good solution.
If you're using java 8, try this:
public static class DicEntry {
String key;
String[] syns;
Pattern pattern;
public DicEntry(String key, String... syns) {
this.key = key;
this.syns = syns;
pattern = Pattern.compile(".*(?:" + Stream.concat(Stream.of(key), Stream.of(syns))
.map(x -> "\\b" + Pattern.quote(x) + "\\b")
.collect(Collectors.joining("|")) + ").*");
}
}
public static void main(String args[]) throws ParseException, IOException {
// Initialization
List<DicEntry> synonymMap = populateSynonymMap();
Scanner scanner = new Scanner(System.in);
// End Initialization
System.out.println("Welcome To DataBase ");
System.out.println("What would you like to know?");
System.out.print("> ");
String input = scanner.nextLine().toLowerCase();
boolean found;
for (DicEntry entry : synonymMap) {
if (entry.pattern.matcher(input).matches()) {
found = true;
System.out.println(entry.key);
parseFile(entry.key);
}
}
}
private static List<DicEntry> populateSynonymMap() {
List<DicEntry> responses = new ArrayList<>();
responses.add(new DicEntry("test", "test load", "quantity of test", "amount of test"));
responses.add(new DicEntry("textbook name", "name of textbook", "text", "portfolio"));
responses.add(new DicEntry("professor office", "room", "post", "place"));
responses.add(new DicEntry("day", "time", "date"));
responses.add(new DicEntry("current assignment", "homework", "current work"));
return responses;
}
Sample output:
Welcome To DataBase
What would you like to know?
> what is the name of textbook that has the homework
textbook name
current assignment
Upvotes: 0
Reputation: 2251
Make a list/append the keys that match. As for the given example , when keyword "textbook" matches store it in a "temp" variable. Now, continue the loop, now keyword "current" matches , append this to variable temp. So, now temp contains "textbook current". Similairly, continue and append the next keyword "assignment" into "temp".
Now, temp contains "textbook current assignment".
Now at the end call the parseFile(temp).
This should work for single or multiple matches.
//Only limitation is the keys are to be given in a ordered sequence , if you want
// to evaluate all the possible combinations then better add all the keys in a list
// And append them in the required combination.
//There might be corner cases which I havent thought of but this might help/point to a more better solution
String temp = "";
//flag - used to indicate whether any word was found in the dictionary or not?
int flag = 0;
for (String ing : inputs) { // iterate over each word of the sentence.
boolean found = false;
for (Map.Entry<String, String[]> entry : synonymMap.entrySet()) {
String key = entry.getKey();
String[] value = entry.getValue();
if (input.contains(key)) {
flag = 1;
found = true;
temp = temp +" "+ key;
}
else if (key.contains(input)) {
flag = 1;
found = true;
temp = temp +" "+ input;
}
else if (Arrays.asList(value).contains(input)) {
flag = 1;
found = true;
temp = temp +" "+ input;
}
}
}
if (flag == 1){
parseFile(temp);
}
Upvotes: 0
Reputation: 3844
I have answered very similar question Understand two or more keys with Hashmaps. But I'll make my point more clear. In the current set of datastructures that you have used lets consider the following structures
1) Input List --> Spilt words in the sentence (may be in order) and keep it in a list example [what,is,the,name,of,textbook,that,has,the,homework]
2) Keyword list --> All keys from the Hashmap database you are using example [test,textbook name,professor office]
Now you have to set some criteria by which you say I can have max 3 words phrase out of sentence (example 'name of textbook')as keyword, why this criteria - to limit the processing, otherwise you'll end up checking lot of combinations of input.
Once you have this, you check whats common in input list and keyword list for criteria you have set. If you don't set criteria then you may try all the combinations against the key set.Once you find single or multiple match, output the synonym list etc.
Example check [name of textbook] against all your keys of the map.
If you want to reverse check, the do the same process by creating a list of synonyms and checking it.
My two tips tackling this problem
1) Define set of keywords and don't check with value list, Hash map structure is not good for that. In this be prepared for redundant data.
2) Set how many words in order you want to search in this keyset. And preferably only keep distinct words.
Hope this helps!
Upvotes: 1