Search code examples
c#.netstringboolean-logicboolean-expression

Turn boolean-expression string into the .NET code


I have logic where customer specifies a string and my app tells to the customer if this string presents in the text, something like this:

internal const string GlobalText = "blablabla";

bool PresentInTheText(string searchString)
{
  return GlobalText.IndexOf(searchString, StringComparison.OrdinalIgnoreCase) >= 0;
}

Basically if text contains passed string return true otherwise false.

Now I want to make it more complex. Lets say if customer passes a string "foo && bar", and I need to return true if this text contains both "foo" and "bar" substrings, straightforward approach:

bool result;
if (!string.IsNullOrEmpty(passedExpression) && 
passedExpression.Contains(" && "))
{
    var tokens = passedExpression.Split(new[] { " && " }, StringSplitOptions.RemoveEmptyEntries);
    result = true;
    foreach (var token in tokens)
    {
        if (GlobalText.IndexOf(token, StringComparison.OrdinalIgnoreCase) < 0)
        {
            result = false;
        }
    }
}
return result;

It works for expressions like A && B && C. But I want generalize the solution to support all boolean operators. Let's say: ("foo" && "bar") || "baz". What would be the solution?

I would say take passed string, using regex add to all strings .IndexOf(token, StringComparison.OrdinalIgnoreCase) < >= 0 code, it would be like this:

("foo".IndexOf(token, StringComparison.OrdinalIgnoreCase) < >= 0 && 
"bar".IndexOf(token, StringComparison.OrdinalIgnoreCase) < >= 0)) ||
"baz".IndexOf(token, StringComparison.OrdinalIgnoreCase) < >= 0

and then turn this string into a function and execute using Reflections. What would be the best solution?

ETA:

Test cases:

bool Contains(string text, string expressionString);

string text = "Customers: David, Danny, Mike, Luke. Car: BMW"

string str0 = "Luke"
string str1 = "(Danny || Jennifer) && (BMW)"
string str2 = "(Mike && BMW) || Volvo"
string str3 = "(Mike || David) && Ford"
string str4 = "David && !BMW"

bool Contains(string text, string str0);  //True - This text contains "Luke"
bool Contains(string text, string str1);  //True - David and BMW in the text
bool Contains(string text, string str2);  //True - Mike and BMW in the text
bool Contains(string text, string str3);  //False - no Ford in the list
bool Contains(string text, string str4);  //False - BMW in the list

Solution

  • You can solve this universally in the same way that a calculator, or a compiler, evaluates an expression:

    1. Tokenize the string and identify each token as an operator (OP) or an operand (A, B, C, etc).
    2. Convert the token sequence from infix (A OP B) to postfix (A B OP).
    3. Evaluate the postfix token sequence.

    Each of these steps can be done with a well known stack based algorithm, in linear time and space. Plus, if you use this method, it automatically extends to any binary operators you'd like to add later (addition, subtraction, fuzzy string match, etc etc).

    To convert from infix to postfix: http://scriptasylum.com/tutorials/infix_postfix/algorithms/infix-postfix/

    To evaluate the postfix: http://scriptasylum.com/tutorials/infix_postfix/algorithms/postfix-evaluation/