Click here to Skip to main content
15,892,537 members
Articles / Desktop Programming / Windows Forms

Evaluation Engine 1.3

Rate me:
Please Sign up or sign in to vote.
4.79/5 (13 votes)
15 Apr 2009CPOL2 min read 40.6K   800   53  
The Evaluation Engine is a parser and interpreter that can be used to build a Business Rules Engine. It allows for mathematical and boolean expressions, operand functions, variables, variable assignment, comments, and short-circuit evaluation. A syntax editor is also included.
using System;
using System.Collections.Generic;
using System.Text;

namespace EvaluationEngine.Support
{
    public class DataTypeCheck
    {

        public static string[] ReservedWords = { "int", "long", "float", "decimal", "currency", "date", "value", "while", "for", "do", "break", "continue", "foreach", "next", "else", "end", "endif", "string", "text", "char", "list", "rule", "expression", "function", "macro", "express", "int", "integer", "list", "sub", "set", ":=" };
        public static string[] OperandFunctions = { "avg", "abs","for","if", "iif", "lcase", "left", "len", "mid", "right", "round", "sqrt", "ucase", "isnullorempty", "istrueornull", "isfalseornull", "trim", "rtrim", "ltrim", "dateadd", "concat", "date", "rpad", "lpad", "join", "searchstring", "day", "month", "year", "substring", "numericmax", "numericmin", "datemax", "datemin", "stringmax", "stringmin", "contains", "between", "indexof", "now", "replace", "eval", "remove", "quote", "pcase", "sin", "cos", "not", "isalldigits" ,"plus"};
        public static string[] ArithOperators = { "^", "*", "/", "%", "+", "-" };
        public static string[] LogicalOperators = { "and", "or" };
        public static string[] ComparisonOperators = { "<", "<=", ">", ">=", "<>", "=="};
        public static string[] AssignmentOperators = { "=" };
        public static string[] BlockSeparator = { "{" , "}" };


        /// <summary>
        /// All digits....no decimals, commas, or -
        /// </summary>
        /// <param name="CheckString"></param>
        /// <returns></returns>
        public static bool IsAllDigits(string CheckString)
        {
            if (String.IsNullOrEmpty(CheckString) == true) return false;

            CheckString = CheckString.Trim();

            bool allDigits = true;
            foreach (char c in CheckString)
            {
                if (Char.IsDigit(c) == false)
                {
                    allDigits = false;
                    break;
                }
            }

            return allDigits;
        }

        /// <summary>
        /// The number of '.' in a string
        /// </summary>
        /// <param name="CheckString"></param>
        /// <returns></returns>
        public static int DecimalCount(string CheckString)
        {
            if (String.IsNullOrEmpty(CheckString) == true) return 0;

            CheckString = CheckString.Trim();

            int decimalCount = 0;
            foreach (char c in CheckString)
            {
                if (c == '.') decimalCount++;
            }

            return decimalCount;
        }


        /// <summary>
        /// Text items are surronded by strings.
        /// </summary>
        /// <param name="CheckString"></param>
        /// <returns></returns>
        public static bool IsText(string CheckString)
        {
            if (String.IsNullOrEmpty(CheckString) == true) return false;

            CheckString = CheckString.Trim();

            if (CheckString.Length == 1) return false;
            if (CheckString.StartsWith("\"") == false) return false;
            if (CheckString.EndsWith("\"") == false) return false;

            return true;
        }


        /// <summary>
        /// integers have all digits and no decimals.  they can also start with -
        /// </summary>
        /// <param name="Token"></param>
        /// <returns></returns>
        public static bool IsInteger(string CheckString)
        {
            if (String.IsNullOrEmpty(CheckString) == true) return false;

            CheckString = CheckString.Trim();
            
            bool isInteger = true;  // assume the value is an integer
            int intPosition = 0; // the current position we are checking

            foreach (char c in CheckString)
            {
                if (Char.IsNumber(c) == false)
                {
                    if (c != '-')
                    {
                        isInteger = false;
                        break;
                    }
                    else if (intPosition != 0)
                    {
                        isInteger = false;
                        break;
                    }
                }

                intPosition++;
            }

            return isInteger;
        }

        public static bool IsDate(string CheckString)
        {

            if (String.IsNullOrEmpty(CheckString) == true) return false;
            CheckString = CheckString.Trim();            

            DateTime d = DateTime.MinValue;
            return DateTime.TryParse(CheckString, out d);
        }

        public static bool IsDouble(string CheckString)
        {

            if (String.IsNullOrEmpty(CheckString) == true) return false;

            CheckString = CheckString.Trim();
            

            bool isDouble = true; // assume the item is a double
            int decimalCount = 0; // the number of decimals

            int intPosition = 0;

            foreach (char c in CheckString)
            {
                if (Char.IsNumber(c) == false)
                {
                    if (c == '.')
                    {
                        decimalCount++;
                    }
                    else if ((c == '-') && (intPosition == 0))
                    {
                        // this is valid, keep going
                    }
                    else
                    {
                        isDouble = false;
                        break;
                    }
                }

                intPosition++;
            }

            if (isDouble == true)
            {
                // make sure there is only 1 decimal

                if (decimalCount <= 1)
                    return true;
                else
                    return false;

            }
            else
                return false;
        }

        public static bool IsReservedWord(string OperandText)
        {
            bool isReservedWord = false;
            if (String.IsNullOrEmpty(OperandText) == true) return false;
            OperandText = OperandText.Trim().ToLower();
            if (String.IsNullOrEmpty(OperandText) == true) return false;

            for (int i = 0; i < ReservedWords.Length; i++)
            {
                if (OperandText == ReservedWords[i])
                {
                    isReservedWord = true;
                    break;
                }
            }

            return isReservedWord;
        }

        public static bool AnyPuncuation(string Text, out Char PuncMark)
        {
            PuncMark = ' ';
            foreach (char c in Text)
            {
                if (Char.IsPunctuation(c) == true)
                {
                    PuncMark = c;
                    return true;
                }
            }

            return false;
        }

        public static bool IsOperandFunction(string OperandText)
        {
            if (String.IsNullOrEmpty(OperandText) == true) return false;

            OperandText = OperandText.Trim().ToLower();

            bool isOperandFunnction = false;

            for (int i = 0; i < OperandFunctions.Length; i++)
            {
                if (OperandText == OperandFunctions[i])
                {
                    isOperandFunnction = true;
                    break;
                }
            }

            return isOperandFunnction;
        }

        public static bool IsOperator(string OperatorText)
        {

            if (String.IsNullOrEmpty(OperatorText) == true) return false;

            OperatorText = OperatorText.Trim().ToLower();
            bool isOperator = false;

            for (int i = 0; i < ArithOperators.Length; i++)
            {
                if (OperatorText == ArithOperators[i])
                {
                    isOperator = true;
                    break;
                }
            }
            if (isOperator == true) return isOperator;



            for (int i = 0; i < LogicalOperators.Length; i++)
            {
                if (OperatorText == LogicalOperators[i])
                {
                    isOperator = true;
                    break;
                }
            }
            if (isOperator == true) return isOperator;



            for (int i = 0; i < ComparisonOperators.Length; i++)
            {
                if (OperatorText == ComparisonOperators[i])
                {
                    isOperator = true;
                    break;
                }
            }
            if (isOperator == true) return isOperator;


            for (int i = 0; i < AssignmentOperators.Length; i++)
            {
                if (OperatorText == AssignmentOperators[i])
                {
                    isOperator = true;
                    break;
                }
            }
            if (isOperator == true) return isOperator;


            return false;
        }

        public static bool IsBoolean(string CheckString)
        {
            if (String.IsNullOrEmpty(CheckString) == true) return false;

            CheckString = CheckString.Trim().ToLower();

            if (CheckString == "true") return true;
            if (CheckString == "false") return true;

            return false;
                    
        }

        public static string RemoveTextQuotes(string CheckString)
        {
            if (IsText(CheckString) == false) return CheckString;

            return CheckString.Substring(1, CheckString.Length - 2);


        }

        public static void FunctionDescription(string FunctionName, out string Syntax, out string Description, out string Example)
        {
            Syntax = "Unknown function";
            Description = "";
            Example = "";
                
            switch (FunctionName.Trim().ToLower())
            {
                case "cos":
                    Description = "Calculates the cosine of a number.";
                    Syntax = "cos[p1] where p1 can be converted to doubles.";
                    Example = "cos[90] < 0";
                    break;

                case "avg":
                    Description = "Calculates the average of a list of numbers.  The list items must be able to convert to doubles.";
                    Syntax = "avg[p1, ..., pn] where p1,...,pn can be converted to doubles.";
                    Example = "avg[1, 2, 3] = 2";
                    break;

                case "abs":
                    Description = "Calculates the absolute value of a numeric parameter.";
                    Syntax = "abs[p1] where p1 can be converted to a double.";
                    Example = "abs[-10] = 10";
                    break;

                case "iif":
                    Description = "Performs an if-else-end";
                    Syntax = "iif[c, a, b] where c is the condition and must evaluate to a boolean.  The value a is returned if c is true, otherwise, the value b is returned.";
                    Example = "iif[year[now[]] = 2008, \"2008\", \"Not 2008\"]";
                    break;

                case "lcase":
                    Description = "Converts a string to lower case";
                    Syntax = "LCase[a]";
                    Example = "LCase[\"TEST\"] = \"test\"";
                    break;

                case "left":
                    Description = "Returns the left number of characters from a string parameter.";
                    Syntax = "left[s, n] where s is the string and n is the number of characters";
                    Example = "left[\"abcd\", 2] = \"ab\"";
                    break;

                case "len":
                    Description = "Returns te length of a string";
                    Syntax = "len[a] where a is a string variable";
                    Example = "len[\"test\"] = 4";
                    break;

                case "mid":
                    Description = "Calculates the median for a list of numbers";
                    Syntax = "mid[p1, ..., pn] where p1, ..., pn are numberic values";
                    Example = "mid[1, 4, 100] = 4";
                    break;

                case "right":
                    Description = "Returns the right number of characters from a string parameter";
                    Syntax = "right[s, n] where s is the string and n is the number of characters.";
                    Example = "right[\"abcd\", 2] = \"cd\"";
                    break;

                case "round":
                    Description = "Rounds a numeric value to the number of decimal places";
                    Syntax = "round[n, d] where n is the numberic value to be rounded, and d is the number of decimal places.";
                    Example = "round[123.45, 0] = 123";
                    break;

                case "sqrt":
                    Description = "Calculates the square root of a number.";
                    Syntax = "sqrt[a] where a is a numberic parameter";
                    Example = "sqrt[25] = 5";
                    break;

                case "ucase":
                    Description = "Converts a string to upper case";
                    Syntax = "ucase[a]";
                    Example = "ucase[\"test\"] = \"TEST\"";
                    break;

                case "isnullorempty":
                    Description = "Indicates is the parameter is null or empty.";
                    Syntax = "IsNullOrEmpty[a]";
                    Example = "";
                    break;

                case "istrueornull":
                    Description = "Indicates if the parameter has the value true or is null;";
                    Syntax = "isTrueorNull[a]"; 
                    Example = "";
                    break;

                case "isfalseornull":
                    Description = "Indicates if the parameter has the value false or is null";
                    Syntax = "IsFalseOrNull[a]";
                    Example = "IIF[IsFalseOrNull[a], \"false\", \"not false\"]";
                    break;

                case "trim":
                    Description = "Trims the spaces from the entire string";
                    Syntax = "trim[a]";
                    Example = "";
                    break;

                case "rtrim":
                    Description = "Trims the spaces from the right of a string";
                    Syntax = "rtrim[a]";
                    Example = "";
                    break;

                case "ltrim":
                    Description = "Trims the spaces from the left of a string";
                    Syntax = "ltrim[a]";
                    Example = "";
                    break;

                case "dateadd":
                    Description = "Adds an amount to a date.  Please note that the amount may be negative.";
                    Syntax = "dateadd[date, \"type\", amount] where date is a valid date, and type is \"y\", \"m\", \"d\" or \"b\" (representing year, month, day, or business days) and amount is an integer";
                    Example = "dateadd[now[], \"b\", 5]";
                    break;

                case "concat":
                    Description = "This operand function concatenates the parameters together to make a string.";
                    Syntax = "concat[p1, ..., pn]";
                    Example = "concat[\"This\", \" \", \"is\", \" \", \"a\", \" \", \"test\"] = \"This is a test\"";
                    break;

                case "date":
                    Description = "Create a new date data type";
                    Syntax = "date[m, d, y] where m is an integer and is the month, d is an integer and is the day, and y is an integer and is the year";
                    Example = "date[3, 20, 2007]";
                    break;

                case "rpad":
                    Description = "Pads a string on the right with new values";
                    Syntax = "rpad[a, b, n]  where a and b are string values and n is numeric.  The parameter p will be appended to the right of parameter a, n times.";
                    Example = "rpad[\"test\", \".\", 10] = \"test..........\"";
                    break;

                case "lpad":
                    Description = "Pads a string on the left with new values";
                    Syntax = "lpad[a, b, n]  where a and b are string values and n is numeric.  The parameter p will be appended to the left of parameter a, n times.";
                    Example = "lpad[\"test\", \".\", 10] = \"..........test\"";
                    break;

                case "join":
                    Description = "Joins a list of items together using a delimiter";
                    Syntax = "join[a, b1, ..., bn] where a is the delimiter and b1, ..., bn are the items to be joined.";
                    Example = "join[\" \", \"This\", \"is\", \"a\", \"test\"] = \"This is a test\"";
                    break;

                case "searchstring":
                    Description = "Searches for a string within another string at a specified starting position";
                    Syntax = "SearchString[a, n, b] where a is the string that is being searched, b is the string that is being sought, and n is the start position in a";
                    Example = "SearchString[\"abcdefghijk\", 0, \"efg\"] = 4";
                    break;

                case "day":
                    Description = "Returns the day of a date";
                    Syntax = "day[d1] where d1 is a date value";
                    Example = "day[3.20.1999] = 20";
                    break;

                case "month":
                    Description = "Returns the month of a date";
                    Syntax = "month[d1] where d1 is a date value";
                    Example = "month[now[]] returns the current month";
                    break;

                case "year":
                    Description = "Returns the year of a date";
                    Syntax = "year[d1] where d1 is a date";
                    Example = "year[now[]] returns the current year";
                    break;

                case "substring":
                    Description = "Extracts a substring from a string";
                    Syntax = "SubString[s, a, b] where s is the string, a is the starting point, and b is the number of characters extracted.";
                    Example = "substring[\"abcdefghijk\", 3, 5] = \"defgh\"";
                    break;

                case "numericmax":
                    Description = "Finds the maximum numeric value in a list";
                    Syntax = "NumericMax[p1, ..., pn]";
                    Example = "";
                    break;

                case "numericmin":
                    Description = "Finds the numeric minimum value in a list";
                    Syntax = "NumericMin[p1, ..., pn]";
                    Example = "";
                    break;

                case "datemax":
                    Description = "Returns the maximum date in the list";
                    Syntax = "datemax[d1, ..., dn] where d1, ..., dn are dates";
                    Example = "datemax[ 3.20.1999, 3.20.2005, 3.20.2008] = 3.20.2008";
                    break;

                case "datemin":
                    Description = "Returns the minimum date in the list.";
                    Syntax = "datemin[d1, ..., dn] where d1, ..., dn are dates.";
                    Example = "datemax[ 3.20.1999, 3.20.2005, 3.20.2008] = 3.20.1999";
                    break;

                case "stringmax":
                    Description = "Finds the maximum string in the list";
                    Syntax = "StringMax[p1, ..., pn]";
                    Example = "StringMax[\"Apple\", \"Zebra\"] = \"Zebra\"";
                    break;

                case "stringmin":
                    Description = "Finds the minimum string in the list";
                    Syntax = "StringMax[p1, ..., pn]";
                    Example = "StringMax[\"Apple\", \"Zebra\"] = \"Apple\"";
                    break;

                case "contains":
                    Description = "Indicates if the item is contained in the list.";
                    Syntax = "contains[p1, p2, ...., pn]   If p1 in in the list p2, ..., pn, this function returns \"true\" otherwise, this function returns \"false\".";
                    Example = "contains[state, \"NY\", \"WA\", \"CA\"] = true";
                    break;

                case "between":
                    Description = "Indicates if a value is between the other values.  Please note that the comparison is inclusive.";
                    Syntax = "between[var, val1, val2] where var, val1, and val2 are integers.  if var >= val1 and var <= val2 then the function returns \"true\", otherwise, the function return \"false\".";
                    Example = "between[fico, 400, 700]   Note that fico is a variable.";
                    break;

                case "indexof":
                    Description = "Returns the index of a list item.";
                    Syntax = "indexof[a, b1, ..., bn]  If the list b1, ..., bn contains the value a, the index of the value is returned, otherwise, -1 is returned.  Pleaes note that this is zero based indexing";
                    Example = "iif[indexof[a, \"CA\", \"NY\", \"WA\"] >= 0, \"found state\", \"not found\"]";
                    break;

                case "now":
                    Description = "Returns the current date";
                    Syntax = "now[]  This operand function takes no parameters";
                    Example = "year[now[]] = 2008";
                    break;

                case "replace":
                    Description = "Replaces one string with another string";
                    Syntax = "Replace[a, b, c] where a is the search string, b is the value being replaced, and c is the value that is being inserted";
                    Example = "replace[\"3.20.2008\", \".\", \"-\"] = \"3-20-2008\"";
                    break;

                case "eval":
                    Description = "Evaluates a string rule";
                    Syntax = "eval[r] where r is any valid rule";
                    Example = "eval[concat[\"1\", \"+\", \"2\"]] = 3";
                    break;

                case "remove":
                    Description = "Removes the specified characters from the string";
                    Syntax = "remove[a, b] where a and b are string";
                    Example = "Remove[\"....this...is..a...test...\", \".a\"] = \"thisistest\"";
                    break;

                case "quote":
                    Description = "Returns a double quote";
                    Syntax = "quote[]";
                    Example = "quote[] = \"";
                    break;

                case "pcase":
                    Description = "Converts a string to Proper Case";
                    Syntax = "pcase[a] where a is a string";
                    Example = "join[\" \", pcase[\"dave\"], pcase[\"SMITH\"] ] = \"Dave Smith\"";
                    break;

                case "sin":
                    Description = "Calcuates the sin of a number";
                    Syntax = "sin[a]";
                    Example = "sin[45] = 0.85";
                    break;

                case "isalldigits":
                    Description = "Determine if the parameter contains all digits.";
                    Syntax = "isalldigits[p1] where p1 is a string parameter";
                    Example = "isalldigits[\"12345\"] = true";
                    break;

                case "not":
                    Description = "Performs a NOT on a boolean parameter.";
                    Syntax = "not[p1] where p1 is a boolean parameter";
                    Example = "not[5<10]=false";
                    break;

            }

        }


        public static bool IsNULL(string CheckString)
        {
            if (String.IsNullOrEmpty(CheckString) == true) return false;
            CheckString = CheckString.Trim().ToLower();

            return (CheckString == "null");

        }

        public static bool ContainsOperator(string CheckString, out string sOperand, out string sOperator)
        {
            // initialize the outgoing variables
            sOperand = "";
            sOperator = "";

            // clean the token
            if (String.IsNullOrEmpty(CheckString) == true) return false;
            CheckString = CheckString.Trim();

            // loop through the arith. operators
            bool containsOperator = false; // assume an operator is not in the opperand
            for (int i = 0; i < Support.DataTypeCheck.ArithOperators.Length; i++)
            {
                if (CheckString.EndsWith(Support.DataTypeCheck.ArithOperators[i]) == true)
                {
                    containsOperator = true;
                    sOperator = Support.DataTypeCheck.ArithOperators[i];
                    sOperand = CheckString.Substring(0, CheckString.Length - sOperator.Length);
                    break;
                }
            }
            if (containsOperator == true) return true;


            // loop through the comparison operators
            for (int i = 0; i < Support.DataTypeCheck.ComparisonOperators.Length; i++)
            {
                if (CheckString.EndsWith(Support.DataTypeCheck.ComparisonOperators[i]) == true)
                {
                    containsOperator = true;
                    sOperator = Support.DataTypeCheck.ComparisonOperators[i];
                    sOperand = CheckString.Substring(0, CheckString.Length - sOperator.Length);
                    break;
                }
            }
            if (containsOperator == true) return true;

            return false;

        }

    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Junior)
Iran (Islamic Republic of) Iran (Islamic Republic of)
he studied MCSD (C# based 2003) and MCDBA (2005) CWNA, CWNP at Sematech
IC Programming with 8051, AVR , IC desighn with FPGA and board desigh at Contronic Co

He also worked on Wireless Low level TCP/IP Programmable Module and video motion Detection algorithm
he is student of Industrial engineering in University of Payam e noor Tehran learning about PMBOK and management systems.
He has Certificate in Advanced English (CAE) and also he studied German language in ökf österreichisches Kulturforum

Comments and Discussions