Click here to Skip to main content
11,576,060 members (57,794 online)
Click here to Skip to main content

math / function / boolean /string expression evaluator

, 19 Mar 2006 149.7K 2.6K 97
Rate this:
Please Sign up or sign in to vote.
C# .NET assembly that executes numeric, date, string, boolean, comparison, etc. expressions.

Introduction

I've come across several expression evaluators on this site. They utilize several clever ideas to implement them, but each of them had their "gotchas". I needed one that was flexible (handled more than one data type), that didn't compile code (too slow and wasted resources), that worked (one couldn't handle any unary operator), and could be easily adapted for other needs.

Thus, I've developed a set of simple classes called ExpressionEval and FunctionEval. These evaluators handle numeric, string, boolean, and datetime datatypes, and they support all the unary and binary operators available in C#. They also support functions (through the utilization of FunctionEval class) and have the ability to add custom functions by attaching an event handler that fires when a function name is not found.

About the project files

Included in the project zip(s) are the .cs files that implement regular expressions, expression evaluation, and function evaluation. Also included is a console based tester application that will allow you to enter and manually test particular expressions.

Simply select the version of the project (VS 2005 or 2003) from the versions above.

API

The API is really simple. You have two main classes: ExpressionEval, and FunctionEval. Both utilize each other to evaluate functions in an expression, or expressions in function parameters.

ExpressionEval has a default constructor and a special constructor to initialize the Expression property. Everything pretty much centers around the Expression property, the SetVariable and ClearVariable methods, the AdditionalFunctionEventHandler event, and the Evaluate() method. There are also some special evaluate methods (i.e. EvaluateBool()) that return a specific data type.

The first time Evaluate() is called, the object creates a graph of the expression to improve performance during subsequent calls of the Evaluate() method. However, if the Expression property changes, it will release the graph and form a new one the next time Evaluate() is called. Therefore, if you are using a consistent expression with changing values, use the SetVariable method so that it will not destroy the graph for the expression.

FunctionEval has a default constructor and a special constructor to initialize the Expression property. Calling Evaluate() will cause the object to find the first function in the Expression property and return its evaluation. Calling the static (or Shared in VB) Replace(string strInput) will cause the object to find all the functions in the input string, and replace them with their evaluations in the output (returned) string. (Note: I added a non-static parameter-less Replace() method that does the same thing, but it uses the Expression property as the source string.)

Both the ExpressionEval class and the FunctionEval class have a public event for handing custom functions. This event fires if a function name in the expression string has no built-in function associated. The event is named AdditionalFunctionEventHandler.

Expression strings

Expression strings are easy to construct. Standard operator precedence applies. (See C# documentation) Parenthesis work. The !, -, and ~ unary operators are functional. To call a function in the expression string use the following syntax: $functioname(param1, param2, ...).

To get a list of the built-in functions, look at the ExecuteFunction method in FunctionEval.cs.

Here are some examples of expression strings:

(1 + 1) * 17 / 3

$now() >= $today()

$pi() == $e()

"Today is " + $fmtdate($today(), "dddd, MMMM d, yyyy")

@(Variable1) == @(Variable2)

!true == false

  • Valid unary operators: -, !, ~.
  • Valid binary operators: *, /, %, +, -, <, <=, >, >=, == (also =), !=, &, ^, !, &&, ||.
  • Parenthesis are evaluated first.
  • E-notation (7.511E-10) is allowed for numbers and...
  • Hexadecimal as well (0xaaf1).
  • Expressions in the form @dt(mm/dd/yyyy hh:mm:ss (AM/PM)) will return a datetime datatype.
  • Expressions in the form @ts([d.]h:m[:s[.ms]]) will return a timespan datatype. tokens in [] are optional.
  • Expressions in the form @(VariableName) will attempt to look up a variable set by SetVariable.

Sample code

In the unit test project, you will see a lot of sample expressions. Here are some example codes for usage:

Construction and evaluation

ExpressionEval expr = new ExpressionEval("1+1");
object val = expr.Evaluate();

Creating a custom function handler

static void eval_AdditionalFunctionEventHandler(
      object sender, AdditionalFunctionEventArgs e)
{
    object[] parameters = e.GetParameters();
    switch (e.Name)
    {
        case "brent":   
            e.ReturnValue = "This Library Rocks!";
            break;

        case "liljohn": 
            e.ReturnValue = "WWWWWWWWHHHHHAT? YEAYAH! OKAY!";
            break;

        case "strcat":
            string ret = "";
            foreach (object parameter in parameters)
                ret += parameter.ToString();
            e.ReturnValue = ret;
            break;

        case "setvar":
            (sender as FunctionEval).SetVariable(
                "" + parameters[0],
                parameters[1]
            );
            break;
    }
}

Using the tester application

Make sure the tester application is set as the startup project. Hit F5 to build and run. You will see a blank console screen. Type in an expression and hit Enter. Its evaluation will appear below it, otherwise an error will be displayed. Type "clr" to clear the console, and type "exit" to quit the application.

Known issues

There is one issue that I am aware of. If you place two binary operators in a row, no error is returned. Instead, the first in the list is used, and the rest until the right operand (w/ or w/o unary operator) are ignored.

Example: (1 * + -1). This will ignore '+' and execute (1 * -1).

Note: I've improved the error handling to catch unused tokens and missing binary operators.

Updates

  • 3/16/2006
    • Added timespan functionality and recognition: @ts([d].h:m[:s[.mmm]]). [] indicates optional components.
    • Added more robust error handling to catch unused tokens and missing binary operators.
  • 12/30/2005
    • Completely updated the code libraries (and verified that it works with the release of VS2005 Pro) and description with bug fixes and modifications that I've been sending to those who had requested for it. Also updated the custom function handling event to .NET event standards. (with sender and eventarg params)
  • 01/05/2005
    • Changed functionality so that upon first execution of an expression (with a created object, not the static (Shared) method), it parses it and creates a graph. As long as the Expression property is not changed, it will keep the graph and, subsequent calls to Evaluate() will not parse the expression, but re-execute the graph.
    • Also added a .NET 2003 ready .zip file.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

railerb
Web Developer
United States United States
No Biography provided

You may also be interested in...

Comments and Discussions

 
QuestionLicense Pin
Member 118079852-Jul-15 3:01
memberMember 118079852-Jul-15 3:01 
QuestionSmart work Pin
Sachin29.g19-Dec-14 14:19
memberSachin29.g19-Dec-14 14:19 
QuestionLicense of the utility Pin
hatake_kakashi2-Jul-14 1:00
memberhatake_kakashi2-Jul-14 1:00 
QuestionString Expression Evaluation Pin
specialdreamsin13-Jun-12 23:06
memberspecialdreamsin13-Jun-12 23:06 
GeneralRe: String Expression Evaluation Pin
railerb17-Jul-12 21:52
memberrailerb17-Jul-12 21:52 
Answerit's wrong some case Pin
thaihuydang27-May-12 22:11
memberthaihuydang27-May-12 22:11 
GeneralRe: it's wrong some case Pin
railerb17-Jul-12 21:50
memberrailerb17-Jul-12 21:50 
GeneralMy vote of 5 Pin
trx128-Sep-11 3:29
membertrx128-Sep-11 3:29 
Generaldecimal Pin
mryapados20-May-10 6:27
membermryapados20-May-10 6:27 
GeneralRe: decimal Pin
ToniB1311-May-11 2:44
memberToniB1311-May-11 2:44 
GeneralRe: decimal Pin
Member 832618217-Oct-11 7:23
memberMember 832618217-Oct-11 7:23 
QuestionUsage of Code [modified] Pin
Member 41913665-Oct-09 2:27
memberMember 41913665-Oct-09 2:27 
QuestionHi...i have a problem... [modified] Pin
linjf52024-Sep-09 17:16
memberlinjf52024-Sep-09 17:16 
GeneralTimeSpan in condition..not working. Pin
rajml4-Sep-09 6:07
memberrajml4-Sep-09 6:07 
GeneralGreat utility Pin
jakka3012-Jun-09 9:53
memberjakka3012-Jun-09 9:53 
GeneralCopyright... Pin
railerb26-Aug-08 12:40
memberrailerb26-Aug-08 12:40 
QuestionCopyright (again) Pin
keesvz20-May-08 8:27
memberkeesvz20-May-08 8:27 
GeneralCommercial Pin
Andreas Freeman15-Apr-08 8:20
memberAndreas Freeman15-Apr-08 8:20 
GeneralBoolean Evaluation Doesn't Like ! Pin
jasona2230-Oct-07 9:46
memberjasona2230-Oct-07 9:46 
GeneralRe: Boolean Evaluation Doesn't Like ! Pin
railerb30-Oct-07 9:50
memberrailerb30-Oct-07 9:50 
QuestionGreat code Pin
nishant.gogia25-Oct-07 6:24
membernishant.gogia25-Oct-07 6:24 
AnswerRe: Date Time Comparison Pin
railerb25-Oct-07 6:29
memberrailerb25-Oct-07 6:29 
QuestionPerformance Pin
kippow18-May-07 12:07
memberkippow18-May-07 12:07 
AnswerRe: Performance Pin
ShCiPwA12315-Aug-07 15:29
memberShCiPwA12315-Aug-07 15:29 
GeneralString Comparison Pin
econner25-Mar-07 10:07
membereconner25-Mar-07 10:07 
NewsAnswer to Copyright... Pin
railerb16-Nov-06 3:17
memberrailerb16-Nov-06 3:17 
QuestionRe: Answer to Copyright... Pin
RanjithPrakash15-Dec-06 2:15
memberRanjithPrakash15-Dec-06 2:15 
GeneralRe: Answer to Copyright... Pin
josevader25-Jan-07 21:05
memberjosevader25-Jan-07 21:05 
Questioncopyright? Pin
erandar15-Nov-06 21:43
membererandar15-Nov-06 21:43 
AnswerRe: copyright? Pin
railerb16-Nov-06 3:17
memberrailerb16-Nov-06 3:17 
GeneralRe: copyright? Pin
tmkhong5-Jan-07 12:55
membertmkhong5-Jan-07 12:55 
QuestionCopyright? Pin
gZanshin1-Nov-06 21:27
membergZanshin1-Nov-06 21:27 
GeneralSecurity issue Pin
Martin Lapierre28-Aug-06 5:50
memberMartin Lapierre28-Aug-06 5:50 
GeneralRe: Security issue Pin
railerb29-Aug-06 11:54
memberrailerb29-Aug-06 11:54 
GeneralBug or at least i though it is Pin
hossamhassan8525-Aug-06 2:05
memberhossamhassan8525-Aug-06 2:05 
GeneralRe: Bug or at least i though it is Pin
railerb28-Aug-06 3:18
memberrailerb28-Aug-06 3:18 
GeneralRe: Bug or at least i though it is Pin
Roberto Ferraris18-Sep-06 5:34
memberRoberto Ferraris18-Sep-06 5:34 
QuestionFunction registry Pin
Koru.nl27-May-06 7:39
memberKoru.nl27-May-06 7:39 
QuestionQuotation characters inside strings? Pin
tola117-May-06 23:49
membertola117-May-06 23:49 
AnswerRe: Quotation characters inside strings? Pin
railerb19-May-06 3:00
memberrailerb19-May-06 3:00 
QuestionEvaluate variable name Pin
underclocker3-Apr-06 7:48
memberunderclocker3-Apr-06 7:48 
AnswerRe: Evaluate variable name Pin
railerb5-Apr-06 6:19
memberrailerb5-Apr-06 6:19 
GeneralRe: Evaluate variable name Pin
underclocker6-Apr-06 6:45
memberunderclocker6-Apr-06 6:45 
Questionstring quotation character Pin
remarcable23-Mar-06 2:45
memberremarcable23-Mar-06 2:45 
AnswerRe: string quotation character Pin
railerb23-Mar-06 3:07
memberrailerb23-Mar-06 3:07 
GeneralTypo; you have ciel instead of ceil Pin
Eric Fontana20-Mar-06 1:14
memberEric Fontana20-Mar-06 1:14 
GeneralA - freaking - mazing. :) Pin
dzCepheus19-Mar-06 23:53
memberdzCepheus19-Mar-06 23:53 
GeneralRe: A - freaking - mazing. :) Pin
Steve Hansen20-Mar-06 0:27
memberSteve Hansen20-Mar-06 0:27 
GeneralRe: A - freaking - mazing. :) Pin
railerb20-Mar-06 2:50
memberrailerb20-Mar-06 2:50 
GeneralRe: A - freaking - mazing. :) Pin
dzCepheus20-Mar-06 2:52
memberdzCepheus20-Mar-06 2:52 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.150603.1 | Last Updated 20 Mar 2006
Article Copyright 2004 by railerb
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid