Dynamic AND conditions in an if statement - java

I have an input String that contains a couple of search terms to find a line in a text including all of the search terms.
For example:
String searchTerms = "java stackoverflow conditions";
String [] splittedTerm = searchTerms.split(" ");
The search terms are AND connective:
if (textLine.contains(splittedTerm[0] && textLine.contains(splittedTerm[1]) && textLine.contains(splittedTerm[2])) start=true;
But the number of search terms is dynamic, it alwayse depends on the users request...
So is there any possibility to use the if statement depending on the number of search terms?

You need to loop through the String[] that you get after splitiing the String :-
First add all the elements you want to compare in an array, then iterate and compare through first array and array returned from split(). Make sure both arrays are of equal length
boolean flag=true;
String searchTerms = "java stackoverflow conditions hello test";
String [] splittedTerm = searchTerms.split(" ");
for(int i=0;i<splittedTerm.length;i++){
if (!(textLine[i].equals(splittedTerm[i]))){ //textLine is the array containing String literals you want to compare.
flag=false;
}
}
start=flag;

you could do a loop which iterates over all search terms. If any missmatch is found, set a flag and break the loop. Below the loop you can then check the flag, if it's still true all of your search terms matched.
boolean flag = true;
for (String searchTerm : splittedTerm){
if (!stringToSearch.contains(searchTerm) {
flag = false;
break;
}
}
if (flag)
all terms matched
else
one or more terms did not match

Related

match exact the same words between 2 strings

I would like to compare and match exactly one word (characters and length) between two strings.
This is what I have:
String wordCompare = "eagle:1,3:7;6\nBasils,45673:ewwsk\nlola:flower:1:2:b";
String lolo = scanner.nextLine();
if ( motCompare.toLowerCase().indexOf(lolo.toLowerCase()) != -1 ) {
System.out.println("Bingo !!!");
} else {
System.out.println("not found !!!");
}
If I type eagle:1,3:7;6 it should display Bingo !!!
If I type eagle:1,3 it still displays Bingo !!! which is wrong, it should display Not found.
If I type eagle:1,3:7;6 Basils,45673:ewwsk or eagle:1,3:7;6\nBasils,45673:ewwsk it should also display Not Found. Length of the typed word should be acknowledged between \n.
If I type Basils,45673:ewwsk, it displays bingo !!!
It looks like what you're wanting is an exact match, with the words being split by the newline character. With that assumption in mind, I would recommend splitting the string out into an array and then loading that into a HashSet like so:
boolean search(String wordDictionary, String search){
String[] options = wordDictionary.split("\n");
HashSet<String> searchSet = new HashSet<String>(Arrays.asList(options));
return searchSet.contains(search);
}
If the search function returns true, it has found whatever word you're searching for, if not, it hasn't.
Installing it in your code will look something like this:
String wordCompare = "eagle:1,3:7;6\nBasils,45673:ewwsk\nlola:flower:1:2:b";
String lolo = scanner.nextLine();
if(search(wordCompare, lolo))
System.out.println("Bingo!!!");
else
System.out.println("Not found.");
(For the record, you'd probably be better off with more clear variable names)
As #Grey has already mentioned within his answer, since you have a newline tag (\n) between your phrases you can Split the String using the String.split() method into a String Array and then compare the elements of that Array for equality with what the User supplies.
The code below is just another example of how this can be done. It also allows for the option to Ignore Letter case:
boolean ignoreCase = false;
String userString = "Basils,45673:ewwsk";
String isInString = "'" + userString + "' Was Not Found !!!";
String wordCompare = "eagle:1,3:7;6\nBasils,45673:ewwsk\nlola:flower:1:2:b";
String[] tmp = wordCompare.split("\n");
for (int i = 0; i < tmp.length; i++) {
// Ternary used for whether or not to ignore letter case.
if (!ignoreCase ? tmp[i].trim().equals(userString) :
tmp[i].trim().equalsIgnoreCase(userString)) {
isInString = "Bingo !!!";
break;
}
}
System.out.println(isInString);
Thank you,
The thing is I am not allowed to use regular expression nor tables.
so basing on your suggestions I made this code :
motCompare.toLowerCase().indexOf(lolo.toLowerCase(), ' ' ) != -1 ||
motCompare.toLowerCase().lastIndexOf(lolo.toLowerCase(),' ' ) != -1)
as a condition for a do while loop.
Could you please confirm if it is correct ?
Thank you.

finding the middle index of a substring when there are duplicates in the string

I was working on a Java coding problem and encountered the following issue.
Problem:
Given a string, does "xyz" appear in the middle of the string? To define middle, we'll say that the number of chars to the left and right of the "xyz" must differ by at most one
xyzMiddle("AAxyzBB") → true
xyzMiddle("AxyzBBB") → false
My Code:
public boolean xyzMiddle(String str) {
boolean result=false;
if(str.length()<3)result=false;
if(str.length()==3 && str.equals("xyz"))result=true;
for(int j=0;j<str.length()-3;j++){
if(str.substring(j,j+3).equals("xyz")){
String rightSide=str.substring(j+3,str.length());
int rightLength=rightSide.length();
String leftSide=str.substring(0,j);
int leftLength=leftSide.length();
int diff=Math.abs(rightLength-leftLength);
if(diff>=0 && diff<=1)result=true;
else result=false;
}
}
return result;
}
Output I am getting:
Running for most of the test cases but failing for certain edge cases involving more than once occurence of "xyz" in the string
Example:
xyzMiddle("xyzxyzAxyzBxyzxyz")
My present method is taking the "xyz" starting at the index 0. I understood the problem. I want a solution where the condition is using only string manipulation functions.
NOTE: I need to solve this using string manipulations like substrings. I am not considering using list, stringbuffer/builder etc. Would appreciate answers which can build up on my code.
There is no need to loop at all, because you only want to check if xyz is in the middle.
The string is of the form
prefix + "xyz" + suffix
The content of the prefix and suffix is irrelevant; the only thing that matters is they differ in length by at most 1.
Depending on the length of the string (and assuming it is at least 3):
Prefix and suffix must have the same length if the (string's length - the length of xyz) is even. In this case:
int prefixLen = (str.length()-3)/2;
result = str.substring(prefixLen, prefixLen+3).equals("xyz");
Otherwise, prefix and suffix differ in length by 1. In this case:
int minPrefixLen = (str.length()-3)/2;
int maxPrefixLen = minPrefixLen+1;
result = str.substring(minPrefixLen, minPrefixLen+3).equals("xyz") || str.substring(maxPrefixLen, maxPrefixLen+3).equals("xyz");
In fact, you don't even need the substring here. You can do it with str.regionMatches instead, and avoid creating the substrings, e.g. for the first case:
result = str.regionMatches(prefixLen, "xyz", 0, 3);
Super easy solution:
Use Apache StringUtils to split the string.
Specifically, splitByWholeSeparatorPreserveAllTokens.
Think about the problem.
Specifically, if the token is in the middle of the string then there must be an even number of tokens returned by the split call (see step 1 above).
Zero counts as an even number here.
If the number of tokens is even, add the lengths of the first group (first half of the tokens) and compare it to the lengths of the second group.
Pay attention to details,
an empty token indicates an occurrence of the token itself.
You can count this as zero length, count as the length of the token, or count it as literally any number as long as you always count it as the same number.
if (lengthFirstHalf == lengthSecondHalf) token is in middle.
Managing your code, I left unchanged the cases str.lengt<3 and str.lengt==3.
Taking inspiration from #Andy's answer, I considered the pattern
prefix+'xyz'+suffix
and, while looking for matches I controlled also if they respect the rule IsMiddle, as you defined it. If a match that respect the rule is found, the loop breaks and return a success, else the loop continue.
public boolean xyzMiddle(String str) {
boolean result=false;
if(str.length()<3)
result=false;
else if(str.length()==3 && str.equals("xyz"))
result=true;
else{
int preLen=-1;
int sufLen=-2;
int k=0;
while(k<str.lenght){
if(str.indexOf('xyz',k)!=-1){
count++;
k=str.indexOf('xyz',k);
//check if match is in the middle
preLen=str.substring(0,k).lenght;
sufLen=str.substring(k+3,str.lenght-1).lenght;
if(preLen==sufLen || preLen==sufLen-1 || preLen==sufLen+1){
result=true;
k=str.length; //breaks the while loop
}
else
result=false;
}
else
k++;
}
}
return result;
}

Search array for value containing all characters(in any order) and return value

I've searched high and low and finally have to ask.
I have an array containing, for example, ["123456","132457", "468591", ... ].
I have a string with a value of "46891".
How do I search through the array and find the object that contains all the characters from my string value? For example the object with "468591" contains all the digits from my string value even though it's not an exact match because there's an added "5" between the "8" and "9".
My initial thought was to split the string into its own array of numbers (i.e. ["4","6","8","9","1"] ), then to search through the array for objects containing the number, to create a new array from it, and to keep whittling it down until I have just one remaining.
Since this is likely a learning assignment, I'll give you an idea instead of an implementation.
Start by defining a function that takes two strings, and returns true if the first one contains all characters of the second in any order, and false otherwise. It should looks like this:
boolean containsAllCharsInAnyOrder(String str, String chars) {
...
}
Inside the function set up a loop that picks characters ch from the chars string one by one, and then uses str.indexOf(ch) to see if the character is present in the string. If the index is non-negative, continue; otherwise, return false.
If the loop finishes without returning, you know that all characters from chars are present in src, so you can return true.
With this function in hand, set up another loop in your main function to go through elements of the array, and call containsAllCharsInAnyOrder on each one in turn.
I think you can use sets for this.
List<String> result = new ArrayList<>();
Set<String> chars = new HashSet<>(Arrays.asList(str.split(""));
for(String string : stringList) {
Set<String> stringListChars = new HashSet<>(Arrays.asList(string.split(""));
if(chars.containsAll(stringListChars)) {
result.add(string);
}
}
There is a caveat here; it doesn't work as you would expect for repeated characters and you haven't specified how you want to handle that (for example, 1154 compared against 154 will be considered a positive match). If you do want to take into account repeated characters and you want to make sure that they exist in the other string, you can use a List instead of a Set:
List<String> result = new ArrayList<>();
List<String> chars = Arrays.asList(str.split(""));
for(String string : stringList) {
List<String> stringListChars = Arrays.asList(string.split("");
if(chars.containsAll(stringListChars)) {
result.add(string);
}
}
Your initial idea was good start, so what you can do is to create not an array but set, then using Guava Sets#powerSet method to create all possible subsets filter only those that have "46891".length mebers, convert each set into String and look those strings in the original array :)
You could do this with the ArrayList containsAll method along with asList:
ArrayList<Character> lookingForChars = new ArrayList<Character>(Arrays.asList(lookingForString.toCharArray()));
for (String toSearchString : array) {
ArrayList<Character> toSearchChars = new ArrayList<Character>(Arrays.asList(toSearchString.toCharArray));
if (toSearchChars.containsAll(lookingForChars)) {
System.out.println("Match Found!");
}
}
You can use String#chartAt() in a nested for loop to compare your string with each of the array's elements.
This method would help you check whether a character is contained in both strings.
This is more tricky then a straigt-forward solution.
The are better algorithms but here one easy to implement and understand.
Ways of solving:
Go through every char at your given string and check if it at the
given arrray.
Collect list for every string from the selected
array containing the given char.
Check if no other char to check.
If there is, Perform A again but on the collected list(result list).
Else, Return all possible matches.
try this
public static void main(String args[]) {
String[] array = {"123456", "132457", "468591"};
String search = "46891";
for (String element : array) {
boolean isPresent = true;
for (int index = 0; index < search.length(); index++) {
if(element.indexOf(search.charAt(index)) == -1){
isPresent = false;
break;
}
}
if(isPresent)
System.out.println("Element "+ element + " Contains Serach String");
else
System.out.println("Element "+ element + " Does not Contains Serach String");
}
}
This sorts the char[]'s of the search string and the and the string to search on. Pretty sure (?) this is O(n logn) vs O(n^2) without sorting.
private static boolean contains(String searchMe, String searchOn){
char[] sm = searchMe.toCharArray();
Arrays.sort(sm);
char[] so = searchOn.toCharArray();
Arrays.sort(so);
boolean found = false;
for(int i = 0; i<so.length; i++){
found = false; // necessary to reset 'found' on subsequent searches
for(int j=0; j<sm.length; j++){
if(sm[j] == so[i]){
// Match! Break to the next char of the search string.
found = true;
break;
}else if(sm[j] > so[i]){ // No need to continue because they are sorted.
break;
}
}
if(!found){
// We can quit here because the arrays are sorted.
// I know if I did not find a match of the current character
// for so in sm, then no other characters will match because they are
// sorted.
break;
}
}
return found;
}
public static void main(String[] args0){
String value = "12345";
String[] testValues = { "34523452346", "1112", "1122009988776655443322",
"54321","7172839405","9495929193"};
System.out.println("\n Search where order does not matter.");
for(String s : testValues){
System.out.println(" Does " + s + " contain " + value + "? " + contains(s , value));
}
}
And the results
Search where order does not matter.
Does 34523452346 contain 12345? false
Does 1112 contain 12345? false
Does 1122009988776655443322 contain 12345? true
Does 54321 contain 12345? true
Does 7172839405 contain 12345? true
Does 9495929193 contain 12345? true

How to know whether a string can be segmented into two strings

I was asked in interview following question. I could not figure out how to approach this question. Please guide me.
Question: How to know whether a string can be segmented into two strings - like breadbanana is segmentable into bread and banana, while breadbanan is not. You will be given a dictionary which contains all the valid words.
Build a trie of the words you have in the dictionary, which will make searching faster.
Search the tree according to the following letters of your input string. When you've found a word, which is in the tree, recursively start from the position after that word in the input string. If you get to the end of the input string, you've found one possible fragmentation. If you got stuck, come back and recursively try another words.
EDIT: sorry, missed the fact, that there must be just two words.
In this case, limit the recursion depth to 2.
The pseudocode for 2 words would be:
T = trie of words in the dictionary
for every word in T, which can be found going down the tree by choosing the next letter of the input string each time we move to the child:
p <- length(word)
if T contains input_string[p:length(intput_string)]:
return true
return false
Assuming you can go down to a child node in the trie in O(1) (ascii indexes of children), you can find all prefixes of the input string in O(n+p), where p is the number of prefixes, and n the length of the input. Upper bound on this is O(n+m), where m is the number of words in dictionary. Checking for containing will take O(w) where w is the length of word, for which the upper bound would be m, so the time complexity of the algorithm is O(nm), since O(n) is distributed in the first phase between all found words.
But because we can't find more than n words in the first phase, the complexity is also limited to O(n^2).
So the search complexity would be O(n*min(n, m))
Before that you need to build the trie which will take O(s), where s is the sum of lengths of words in the dictionary. The upper bound on this is O(n*m), since the maximum length of every word is n.
you go through your dictionary and compare every term as a substring with the original term e.g. "breadbanana". If the first term matches with the first substring, cut the first term out of the original search term and compare the next dictionary entries with the rest of the original term...
let me try to explain that in java:
e.g.
String dictTerm = "bread";
String original = "breadbanana";
// first part matches
if (dictTerm.equals(original.substring(0, dictTerm.length()))) {
// first part matches, get the rest
String lastPart = original.substring(dictTerm.length());
String nextDictTerm = "banana";
if (nextDictTerm.equals(lastPart)) {
System.out.println("String " + original +
" contains the dictionary terms " +
dictTerm + " and " + lastPart);
}
}
The simplest solution:
Split the string between every pair of consecutive characters and see whether or not both substrings (to the left of the split point and to the right of it) are in the dictionary.
One approach could be:
Put all elements of dictionary in some set or list
now you can use contains & substring function to remove words which matches dictionary. if at the end string is null -> string can be segmented else not. You can also take care of count.
public boolean canBeSegmented(String s) {
for (String word : dictionary.getWords()) {
if (s.contains(word) {
String sub = s.subString(0, s.indexOf(word));
s = sub + s.subString(s.indexOf(word)+word.length(), s.length()-1);
}
return s.equals("");
}
}
This code checks if your given String can be fully segmented. It checks if a word from the dictionary is inside your string and then subtracks it. If you want to segment it in the process you have to order the subtracted sementents in the order they are inside the word.
Just two words makes it easier:
public boolean canBeSegmented(String s) {
boolean wordDetected = false;
for (String word : dictionary.getWords()) {
if (s.contains(word) {
String sub = s.subString(0, s.indexOf(word));
s = sub + s.subString(s.indexOf(word)+word.length(), s.length()-1);
if(!wordDetected)
wordDetected = true;
else
return s.equals("");
}
return false;
}
}
This code checks for one Word and if there is another word in the String and just these two words it returns true otherwise false.
this is a mere idea , you can implement it better if you want
package farzi;
import java.util.ArrayList;
public class StringPossibility {
public static void main(String[] args) {
String str = "breadbanana";
ArrayList<String> dict = new ArrayList<String>();
dict.add("bread");
dict.add("banana");
for(int i=0;i<str.length();i++)
{
String word1 = str.substring(0,i);
String word2 = str.substring(i,str.length());
System.out.println(word1+"===>>>"+word2);
if(dict.contains(word1))
{
System.out.println("word 1 found : "+word1+" at index "+i);
}
if(dict.contains(word2))
{
System.out.println("word 2 found : "+ word2+" at index "+i);
}
}
}
}

Regular expression for validating an answer to a question

Hey everyone,
I'm having a minor difficulty setting up a regular expression that evaluates a sentence entered by a user in a textbox to keyword(s). Essentially, the keywords have to be entered consecutive from one to the other and can have any number of characters or spaces before, between, and after (ie. if the keywords are "crow" and "feet", crow must be somewhere in the sentence before feet. So with that in mind, this statement should be valid "blah blah sccui crow dsj feet "). The characters and to some extent, the spaces (i would like the keywords to have at least one space buffer in the beginning and end) are completely optional, the main concern is whether the keywords were entered in their proper order.
So far, I was able to have my regular expression work in a sentence but failed to work if the answer itself was entered only.
I have the regular expression used in the function below:
// Comparing an answer with the right solution
protected boolean checkAnswer(String a, String s) {
boolean result = false;
//Used to determine if the solution is more than one word
String temp[] = s.split(" ");
//If only one word or letter
if(temp.length == 1)
{
if (s.length() == 1) {
// check multiple choice questions
if (a.equalsIgnoreCase(s)) result = true;
else result = false;
}
else {
// check short answer questions
if ((a.toLowerCase()).matches(".*?\\s*?" + s.toLowerCase() + "\\s*?.*?")) result = true;
else result = false;
}
}
else
{
int count = temp.length;
//Regular expression used to
String regex=".*?\\s*?";
for(int i = 0; i<count;i++)
regex+=temp[i].toLowerCase()+"\\s*?.*?";
//regex+=".*?";
System.out.println(regex);
if ((a.toLowerCase()).matches(regex)) result = true;
else result = false;
}
return result;
Any help would greatly be appreciated.
Thanks.
I would go about this in a different way. Instead of trying to use one regular expression, why not use something similar to:
String answer = ... // get the user's answer
if( answer.indexOf("crow") < answer.indexOf("feet") ) {
// "correct" answer
}
You'll still need to tokenize the words in the correct answer, then check in a loop to see if the index of each word is less than the index of the following word.
I don't think you need to split the result on " ".
If I understand correctly, you should be able to do something like
String regex="^.*crow.*\\s+.*feet.*"
The problem with the above is that it will match "feetcrow feetcrow".
Maybe something like
String regex="^.*\\s+crow.*\\s+feet\\s+.*"
That will enforce that the word is there as opposed to just in a random block of characters.
Depending on the complexity Bill's answer might be the fastest solution. If you'd prefer a regular expression, I wouldn't look for any spaces, but word boundaries instead. That way you won't have to handle commas, dots, etc. as well:
String regex = "\\bcrow(?:\\b.*\\b)?feet\\b"
This should match "crow bla feet" as well as "crowfeet" and "crow, feet".
Having to match multiple words in a specific order you could just join them together using '(?:\b.*\b)?' without requiring any additional sorting or checking.
Following Bill answer, I'd try this:
String input = // get user input
String[] tokens = input.split(" ");
String key1 = "crow";
String key2 = "feet";
String[] tokens = input.split(" ");
List<String> list = Arrays.asList(tokens);
return list.indexOf(key1) < list.indexOf(key2)

Categories