Home > front end >  How to parse Logical Operators from the string and find the matches in the given List
How to parse Logical Operators from the string and find the matches in the given List

Time:03-11

I want to write a method that takes as an input a String key separated by a white spaces and a list of String in which matches have to be searched.

The format of the string key could be like this:

"s1 or s2 s3 or s4"

It has to be translated to a condition "(s1 or s2) and (s3 or s4)", where conditions grouped with or are always executed first.

The method should return a list of strings which match the condition obtained from the specified the "key".

public List<String> search(String key, ArrayList<String> s){
    ...
}

Example of the input (a key and a list):

// if ((s.contains("i") || s.contains("you")) && (s.contains("boy") || s.contains("girl")) then store in the List and return finally
String key = "i or you boy or girl"; 

ArrayList<String> s = new ArrayList<String>(
            Arrays.asList("hello world",
                          "i am a boy",
                          "i am a girl"));

Then the resulting list would contain string:

`"i am a boy"` and `"i am a girl"`.

I really don't know how to retrieve logical operators from the string so that I could perform the comparison.

CodePudding user response:

It can be done with predicates (function represented by a boolean condition) and regular expressions.

The overall idea is to generator a Predicate based on string key and then to test list elements against this predicate.

The process of parsing a Predicate is done in following steps:

  • Split the key into groups, that has to be combined afterwards with logical AND, based on following regular expression "(?<!or)\\s (?!or)"
    • (?<!or) - negative lookbehind, represents group of characters before the matching string that must not be equal to "or";
    • (?!or) - negative lookahead, represents group of characters after the matching string that must not be equal to "or";
    • \\s - matches a string comprised from one or more white spaces.
  • Split each group of strings obtained at the previous step on the " or " and combine the obtained predicates with logical OR.
  • Combine predicates generated at previous step into a single predicate.

(for information on regular expressions take a look at this tutorial)

Then we need to iterate over the given list and apply method test() of the combined predicate to every element. Elements that meet with the predicate will be added into the resulting list.

public static void main(String[] args) {
    String key = "i or you boy or girl";

    List<String> source =
            List.of("hello world", "i am a boy", "i am a girl");

    Predicate<String> predicate = getPredicate(key);
    List<String> result = new ArrayList<>();

    for (String next: source) {
        if (predicate.test(next)) {
            result.add(next);
        }
    }
    System.out.println(result);
}

public static Predicate<String> getPredicate(String key) {
    Predicate<String> result = str -> true;

    for (String next: key.split("(?<!or)\\s (?!or)")) {
        Predicate<String> pred = str -> false;

        for (String target: next.strip().split(" or ")) {
            if (target.isEmpty()) {
                continue;
            }
            pred = pred.or(str -> str.contains(target));
        }
        result = result.and(pred);
    }
    return result;
}

Output

[i am a boy, i am a girl]

Note:

  • A base for combining predicates with or (||) has to yield false because only in this case it'll not affect the result (with (||) only one condition can be true and the overall result will be evaluated to true).
  • A base for combining predicates with and (&&) has to return true because only so the result will not get affected (with && all the conditions needs to be evaluated to true for the overall result to be true).
  • Related