PSC.Evaluator
1.0.0
dotnet add package PSC.Evaluator --version 1.0.0
NuGet\Install-Package PSC.Evaluator -Version 1.0.0
<PackageReference Include="PSC.Evaluator" Version="1.0.0" />
paket add PSC.Evaluator --version 1.0.0
#r "nuget: PSC.Evaluator, 1.0.0"
// Install PSC.Evaluator as a Cake Addin #addin nuget:?package=PSC.Evaluator&version=1.0.0 // Install PSC.Evaluator as a Cake Tool #tool nuget:?package=PSC.Evaluator&version=1.0.0
PureSourceCode Evaluator
PSC.Evaluator is a mathematical expressions evaluator library written in C#. Allows to evaluate mathematical, boolean, string and datetime expressions.
Code is written in pure C# based on .NET Standard, run on the fly. We don't use any third party libraries or packages.
Installation
Using Package Manager
PM> Install-Package PSC.Evaluator
Usage examples
Basic evaluator
using System;
using PSC.Evaluator;
public class Program
{
public static void Main()
{
Expression expression = new Expression("(a + b) / 2 ");
expression.Bind("a", 3);
expression.Bind("b",5);
Object value = expression.Eval();
Console.WriteLine("Result: "+value); // Result: 4
}
}
Conditional statements
using System;
using PSC.Evaluator;
public class Program
{
public static void Main()
{
Expression expression = new Expression("IF(time>8, (HOUR_SALARY*8) + (HOUR_SALARY*1.25*(time-8)), HOUR_SALARY*time)");
// bind variable
expression.Bind("HOUR_SALARY", 10);
expression.Bind("time", 9);
// eval
Decimal salary = expression.Eval<Decimal>();
Console.WriteLine(salary); // return 92.5
}
}
Validate expression
Expression expression = new Expression("SUM(1,2,3) + true");
List<String> errors = expression.GetError();
if(errors.Count > 0)
{
foreach(String error in errors)
{
Console.WriteLine(error);
}
}
Min, max, sum, avg
using System;
using PSC.Evaluator;
public class Program
{
public static void Main()
{
Expression expr = new Expression("MIN(2,3,16)");
int min = expr.Eval<int>();
Console.WriteLine(min); // return 2 (min)
expr.SetFomular("Max(2,3,16)");
int max = expr.Eval<int>();
Console.WriteLine(max); // return 16 (max)
expr.SetFomular("Sum(2,3,16)");
decimal sum = expr.Eval<decimal>();
Console.WriteLine(sum); // return 21 (sum)
expr.SetFomular("average(2,3,16)");
decimal average = expr.Eval<decimal>();
Console.WriteLine(average); // return 7 (average)
}
}
Round, floor, ceiling
using System;
using PSC.Evaluator;
public class Program
{
public static void Main()
{
Expression expr = new Expression("ROUND(2.149, 1)");
Object value = expr.Eval<Decimal>();
Console.WriteLine("ROUND(2.149, 1) = "+value); //return 2.1
expr = new Expression("FLOOR(2.149)");
value = expr.Eval();
Console.WriteLine("FLOOR(2.149) = "+value); //return 2
expr = new Expression("FLOOR(3.7,2)");
value = expr.Eval();
Console.WriteLine("FLOOR(3.7,2) = "+value); //return 2
expr = new Expression("CEILING(2.149)");
value = expr.Eval();
Console.WriteLine("CEILING(2.149) = "+value); //return 3
expr = new Expression("CEILING(1.5, 0.1)");
value = expr.Eval();
Console.WriteLine("CEILING(1.5, 0.1) = "+value); //return 1.5
}
}
Trigonometry
using System;
using PSC.Evaluator;
public class Program
{
public static void Main()
{
Expression expr = new Expression("tan(a)^3-((3*sin(a)-sin(3*a))/(3*cos(a)+cos(3*a)))");
Decimal value = expr.Bind("a", Math.PI/6).Eval<Decimal>();
Console.WriteLine(value); // return 0
}
}
Deal with string
using System;
using PSC.Evaluator;
public class Program
{
public static void Main()
{
Expression taxExpr = new Expression("IF(LOWER(TAX_CODE)='vat',amount*10/100,IF(LOWER(TAX_CODE)='gst',amount*15/100,0))");
taxExpr.Bind("TAX_CODE","GST");
taxExpr.Bind("amount", 5005m);
Decimal value = taxExpr.Eval<Decimal>();
Console.WriteLine(value);
}
}
Concatenate strings
using System;
using PSC.Evaluator;
public class Program
{
public static void Main()
{
Expression expr = new Expression("CONCAT('The United States of ', 'America')");
String value = expr.Eval<String>();
Console.WriteLine(value); // The United States of America
}
}
Documentation
- Object initialization
Expression expression = new Expression("(a + b) / 2 ");
or using default constructor + SetFomular()
method:
Expression expression = new Expression();
expression.SetFomular("(a + b) / 2 ");
- Bind variable
Expression expression = new Expression("(a + b) / 2 ");
expression.Bind("a", 3).Bind("b",5);
3. Eval expression c#
Expression expression = new Expression("(a + b) / 2 ");
expression.Bind("a", 3);
expression.Bind("b",5);
Object value = expression.Eval(); // will return 4
4. Multiple methods just in one line (method chaining)
Object value = new Expression("(a + b) / 2 ").Bind("a", 3).Bind("b", 5).Eval();
5. Using conditional statements
IF/ELSE condition
Expression expression = new Expression("IF(time>8, (HOUR_SALARY*8) + (HOUR_SALARY*1.25*(time-8)), HOUR_SALARY*time)");
// bind variable
expression.Bind("HOUR_SALARY", 10);
expression.Bind("time", 9);
// eval
Decimal salary = expression.Eval<Decimal>(); // will return 92.5
SWITCH/CASE condition
Expression expr = new Expression("SWITCH(name,1,'apple',2,'mango',3,'banana','N/A')");
// bind variable
expr.Bind("name", 2);
// eval
String value = expr.Eval<String>(); // return "mango"
6. Validate expression before evaluate
Expression expression = new Expression("SUM(1,2,3) + true");
// validate expression
List<String> errors = expression.GetError();
if(errors.Count == 0)
{
// No error
}
7. Get variables that appear in the expression
Expression expression = new Expression("sin(pi/2+x)-cos(x) = a");
// validate expression
List<String> errors = expression.GetError();
if (errors.Count == 0)
{
// get variables
List<String> variables = expression.getVariables();
foreach (String variable in variables)
{
Console.WriteLine(variable); // will print x, a
}
}
8. Disable functions
Expression expression = new Expression();
expression.DisableFunction("SIN");
expression.DisableFunction("COS");
or
Expression expression = new Expression();
expression.DisableFunction(new string[] { "SIN", "COS" });
9. Work with number expression
Example 1: Scale and rounding mode
Use setScale() method to set number of digits to the right of the decimal point. Use setRoundingMode() method to set rounding mode. You can choose 1 of the following options:
- MidpointRounding.AwayFromZero
- MidpointRounding.ToEven
- MidpointRounding.ToZero
Expression expression = new Expression("pi/2");
expression.SetScale(3);
expression.SetRoundingMode(MidpointRounding.ToEven);
Decimal value = expression.Eval<Decimal>(); // return 1.571
Example 2: Simple expression
Expression expr = new Expression('(a+b+c)/2');
expr.Bind("a",2);
expr.Bind("b",3);
expr.Bind("c",16);
Object value = expr.Eval(); // return 10.5
Example 3: Complex expression
Expression expr = new Expression("tan(a)^3-((3*sin(a)-sin(3*a))/(3*cos(a)+cos(3*a)))");
expr.Bind("a", System.Math.PI / 4);
Object value = expr.Eval(); // return 0
Example 4: Min, max
Expression expr = new Expression("MIN(a,b,c)");
expr.Bind("a", 2);
expr.Bind("b", 3);
expr.Bind("c", 16);
int value = expr.Eval<int>(); // return 2
Example 5: Min, max with collection variable
Expression expr = new Expression("MAX(a)");
expr.Bind("a", new List<Decimal> { 10m, 9.6m, 135, 724.2m, 6m, -4m });
Decimal value = expr.Eval<Decimal>(); // return 724.2
Example 6: Sum, average
Expression expr = new Expression("SUM(a,b,c)");
expr.Bind("a", 2d);
expr.Bind("b", 3d);
expr.Bind("c", 16d);
Double sum = expr.Eval<Double>(); // return 21
expr.SetFomular("AVERAGE(a,b,c)");
Double avg = expr.Eval<Double>(); // return 7
Example 7: Sum, average using collection variable
Expression expr = new Expression("SUM(a)");
expr.Bind("a", new List<Decimal> { 2m, 3m, 16m });
Decimal sum = expr.Eval<Decimal>(); // return 21
expr.SetFomular("AVERAGE(a)");
Decimal avg = expr.Eval<Decimal>(); // return 7
Example 8: Round, Floor, Ceiling
Expression expr = new Expression("ROUND(2.149, 1)");
Object value = expr.Eval(); // return 2.1
Expression expr = new Expression("FLOOR(2.149)");
Object value = expr.Eval(); // return 2
// Rounds 3.7 down to nearest multiple of 2
Expression expr = new Expression("FLOOR(3.7,2)");
Object value = expr.Eval(); // return 2
Expression expr = new Expression("CEILING(2.149)");
Object value = expr.Eval(); // return 3
// Rounds 1.5 up to the nearest multiple of 0.1
Expression expr = new Expression("CEILING(1.5, 0.1)");
Object value = expr.Eval(); // return 1.5
Example 9: Trigonometry calculation
Expression expr = new Expression('SIN(PI())^2+COS(PI())^2');
Object value = expr.Eval(); // return 1
Expression expr = new Expression("sin(a) - cos(a) = SQRT(2) * sin(a - pi / 4)");
bool value = expr.Bind("a", Math.PI/5).Eval<bool>(); // return true
Expression expr = new Expression("tan(a)^3-((3*sin(a)-sin(3*a))/(3*cos(a)+cos(3*a)))");
Decimal value = expr.Bind("a", Math.PI/6).Eval<Decimal>(); // return 0
Example 10: Unary operator
Expression expr = new Expression("3--2+--3-(-(++2))");
Object value = expr.Eval(); // return 10
10. Work with string
Example 1: Left, right
Expression expr = new Expression("IF(VALUE(LEFT(date,4))<2020,'n/a','generation of ' & LEFT(date,4))");
expr.Bind("date", "2022-01-20");
String value = expr.Eval<String>();
Example 2: Calculate tax
Expression taxExpr = new Expression("IF(LOWER(TAX_CODE)='vat',amount*10/100,IF(LOWER(TAX_CODE)='gst',amount*15/100,0))");
taxExpr.Bind("TAX_CODE","GST");
taxExpr.Bind("amount", 5005m);
Decimal value = taxExpr.Eval<Decimal>();
Example 3: Concatenate strings
Expression expr = new Expression("CONCAT('The United States of ', 'America')");
String value = expr.Eval<String>(); // The United States of America
11. Work with datetime
December 30, 1899 date system
We use 1899 date system, the first day that is supported is December 30, 1899. Any date you supply to this library will be converted into a serial number that represents the number of elapsed days starting from December 30, 1899. Look at the sample below:
Expression expr = new Expression("DATETIME(2025,01,02,12,11,10)");
Decimal serialDate = expr.Eval<Decimal>(); // return 45659.507755 (days elapsed from December 30, 1899)
DateTime datetime = expr.Eval<DateTime>(); // return 2025/01/02 12:11:10
Setting holidays and weekend for expression context
Expression expr = new Expression("NETWORKDAYS(B5,C5)");
expr.SetHolidays(
new DateTime[] {
new DateTime(2017,11,23),
new DateTime(2017, 12, 25),
new DateTime(2018, 1, 1)
}
);
expr.SetWeekends(new Int32[] { 1, 2, 3 }); // Sunday = 0, ..., Saturday = 6
expr.Bind("B5", new DateTime(2017, 1, 15));
expr.Bind("C5", new DateTime(2018, 1, 21));
Decimal value = expr.Eval<Decimal>(); // return 212
Example 1: Calculate networkday
Expression expr = new Expression("NETWORKDAYS(DATEVALUE('2021-03-30'),DATEVALUE('2022-05-16'))");
int value = expr.Eval<int>(); // return 295
Expression expr = new Expression("NETWORKDAYS(startdate,enddate)");
expr.Bind("startdate", new DateTime(2021, 08, 11));
expr.Bind("enddate", new DateTime(2021, 10, 4));
Object value = expr.Eval(); // return 39
Example 2: Calculates the number of days, months, or years between two dates.
Expression expr = new Expression("DATEDIFF(DATEVALUE('2021-01-31'),DATEVALUE('2029-08-29'),'Y')");
Object value = expr.Eval(); // return 8
Expression expr = new Expression("DATEDIFF(DATEVALUE('2021-01-31'),DATEVALUE('2029-08-29'),'M')");
Object value = expr.Eval(); // return 102
Expression expr = new Expression("DATEDIFF(DATEVALUE('2021-01-31'),DATEVALUE('2029-08-29'),'D')");
Object value = expr.Eval(); // return 3132
Expression expr = new Expression("DATEDIFF(DATEVALUE('2021-01-31'),DATEVALUE('2029-08-29'),'MD')");
Object value = expr.Eval(); // return 29
Example 3: Calculates the number of days, hours, mins between two datetime.
Expression expr = new Expression("DATETIME(2021,2,28,15,50,0)-DATETIME(2021,2,21,23,0,0)");
Decimal value = expr.Eval<Decimal>(); // return 6.70139 (days)
Expression expr = new Expression("(DATETIME(2021,2,28,15,50,0)-DATETIME(2021,2,21,23,0,0))*24");
Decimal value = expr.Eval<Decimal>(); // return 160.8 (hours)
Expression expr = new Expression("(DATETIME(2021,2,28,15,50,0)-DATETIME(2021,2,21,23,0,0))*24*60");
Decimal value = expr.Eval<Decimal>(); // return 9650 (mins)
Example 4: Calculates the number of days, hours, mins between two timespan.
Expression expr = new Expression("(endtime-TIME(17,0,0))*24*60");
expr.Bind("endtime", new TimeSpan(18, 20, 0));
Decimal value = expr.Eval<Decimal>(); // return 80 (mins)
Example5: Substract, add datetime
Expression expr = new Expression("DATETIME(2021,2,28,15,50,0)-DATETIME(2021,2,21,23,0,0)");
Object value = expr.Eval(); // return 6.701389 (days)
Expression expr = new Expression("DATE(2021,2,28)-DATE(2021,2,21)");
Object value = expr.Eval(); // return 7 (days)
Expression expr = new Expression("DATE(2021,9,20)+3");
DateTime value = expr.Eval<DateTime>(); // return 2021-09-23
Expression expr = new Expression("TIME(10,10,0)+TIME(10,10,0)");
TimeSpan value = expr.Eval<TimeSpan>(); // return 20:20:00
12. Supported operators, constants and functions in this expression evaluator library
Supported Operators
Operator | Description |
---|---|
+ | Additive operator / Unary plus / Concatenate string / Datetime addition |
& | Concatenate string |
– | Subtraction operator / Unary minus / Datetime subtraction |
* | Multiplication operator, can be omitted in front of an open bracket |
/ | Division operator |
% | Remainder operator (Modulo) |
^ | Power operator |
Supported conditional statements
Conditional statement | Description |
---|---|
IF(logical_condition, value_if_true, value_if_false) | Example: <br>IF(2>1,"Pass","Fail") |
SWITCH(expression, val1,result1, [val2,result2], …, [default]) | Example: <br>SWITCH(3+2,5,"Apple",7,"Mango",3,"Good","N/A") |
Supported logical and math functions
Function | Description |
---|---|
AND(logical1, [logical2], …) | Determine if all conditions are TRUE |
OR(logical1, [logical2], …) | Determine if any conditions in a test are TRUE |
NOT(logical) | To confirm one value is not equal to another |
XOR(logical1, [logical2], …) | Exclusive OR function |
SUM(number1, [number2],…) | Return sum of numbers supplied |
AVERAGE(number1, [number2],…) | Return average of numbers supplied |
MIN(number1, [number2],…) | Return the smallest value from the numbers supplied |
MAX(number1, [number2],…) | Return the biggest value from the numbers supplied |
MOD(number, divisor) | Get remainder of two given numbers after division operator. |
ROUND(number, num_digits) | Returns the rounded approximation of given number using half-even rounding mode <br>( you can change to another rounding mode) |
FLOOR(number, significance) | Rounds a given number towards zero to the nearest multiple of a specified significance |
CEILING(number, significance) | Rounds a given number away from zero, to the nearest multiple of a given number |
POWER(number, power) | Returns the result of a number raised to a given power |
RAND() | Produces a random number between 0 and 1 |
SIN(number) | Returns the trigonometric sine of the angle given in radians |
SINH(number) | Returns the hyperbolic sine of a number |
ASIN(number) | Returns the arc sine of an angle, in the range of -pi/2 through pi/2 |
COS(number) | Returns the trigonometric cos of the angle given in radians |
COSH(number) | Returns the hyperbolic cos of a number |
ACOS(number) | Returns the arc cosine of an angle, in the range of 0.0 through pi |
TAN(number) | Returns the tangent of the angle given in radians |
TANH(number) | Returns the hyperbolic tangent of a number |
ATAN(number) | Returns the arc tangent of an angle given in radians |
ATAN2(x_number, y_number) | Returns the arctangent from x- and y-coordinates |
COT(number) | Returns the cotangent of an angle given in radians. |
COTH(number) | Returns the hyperbolic cotangent of a number |
SQRT(number) | Returns the correctly rounded positive square root of given number |
LN(number) | Returns the natural logarithm (base e) of given number |
LOG10(number) | Returns the logarithm (base 10) of given number |
EXP(number) | Returns e raised to the power of given number |
ABS(number) | Returns the absolute value of given number |
FACT(number) | Returns the factorial of a given number |
SEC(number) | Returns the secant of an angle given in radians |
CSC(number) | Returns the cosecant of an angle given in radians |
PI() | Return value of Pi |
RADIANS (degrees) | Convert degrees to radians |
DEGREES (radians) | Convert radians to degrees |
INT(number) | Returns the Integer value of given number |
Supported Constants
Constant | Description |
---|---|
e | The value of e |
PI | The value of PI |
TRUE | The boolean true value |
FALSE | The boolean false value |
NULL | The null value |
Supported text functions
Function | Description |
---|---|
LEFT(text, num_chars) | Extracts a given number of characters from the left side of a supplied text string |
RIGHT(text, num_chars) | Extracts a given number of characters from the right side of a supplied text string |
MID(text, start_num, num_chars) | Extracts a given number of characters from the middle of a supplied text string |
REVERSE(text) | Reverse a string |
ISNUMBER(text) | Check if a value is a number |
LOWER(text) | Converts all letters in the specified string to lowercase |
UPPER(text) | Converts all letters in the specified string to uppercase |
PROPER(text) | Capitalizes words given text string |
TRIM(text) | Removes extra spaces from text |
LEN(text) | Returns the length of a string/ text |
TEXT(value, [format_text]) | Convert a numeric value into a text string. You can use the TEXT function to embed formatted numbers inside text <br><br>Example:<br>TEXT(123) -> 123 <br><br>TEXT(123) -> 123 <br><br>TEXT(DATEVALUE("2021-01-23"),"dd-MM-yyyy") -> 23-01-2021 <br><br>TEXT(DATEVALUE("2021-01-23"),"dd-MM-yyyy") -> 23-01-2021 <br><br>TEXT(2.61,"hh:mm") -> 14:38 <br><br>TEXT(2.61,"hh:mm") -> 14:38 <br><br>TEXT(2.61,"[hh]") -> 62 <br><br>TEXT(2.61,"[hh]") -> 62 <br><br>TEXT(2.61,"hh-mm-ss") -> 14-38-24 <br><br>TEXT(2.61,"hh-mm-ss") -> 14-38-24 <br><br>TEXT(DATEVALUE("2021-01-03")-DATEVALUE("2021-01-01"),"[h]") -> 48 <br><br>TEXT(DATEVALUE("2021-01-03")-DATEVALUE("2021-01-01"),"[h]") -> 48 <br><br>TEXT(TIME(12,00,00)-TIME(10,30,10),"hh hours and mm minutes and ss seconds") -> "01 hours and 29 minutes and 50 seconds" <br><br>TEXT(TIME(12,00,00)-TIME(10,30,10),"hh hours and mm minutes and ss seconds") -> "01 hours and 29 minutes and 50 seconds" |
REPLACE(old_text, start_num, num_chars, new_text) | Replaces characters specified by location in a given text string with another text string |
SUBSTITUTE(text, old_text, new_text) | Replaces a set of characters with another |
FIND(find_text, within_text, [start_num]) | Returns the location of a substring in a string (case sensitive) |
SEARCH(find_text, within_text, [start_num]) | Returns the location of a substring in a string (case insensitive) |
CONCAT(text1, text2, text3,…) | Combines the text from multiple strings |
ISBLANK(text) | Returns TRUE when a given string is null or empty, otherwise return FALSE |
REPT(text, repeat_time) | Repeats characters a given number of times |
CHAR(char_code) | Return character from ascii code |
CODE(char) | Returns a ascii code of a character |
VALUE(text) | Convert numbers stored as text to numbers |
Supported date&time functions
Function | Description |
---|---|
DATE(year,month,day) | Constructs a Date from Integer representations of the year, month (1=Jan), and day |
DATEVALUE(date_string) | Constructs a Date from String representations of the year–month–day |
TIME(hour,min,second) | Constructs a Time instance from Integer representations of the hour, minute, and second |
SECOND(time_instance) <br>SECOND(datetime_instance) | Returns the second component of a Time, Datetime |
MINUTE(time_instance) <br>MINUTE(datetime_instance) | Returns the minute component of a Time, Datetime |
HOUR(time_instance) <br>HOUR(datetime_instance) | Returns the hour component of a Time, Datetime |
DAY(date_instance) <br>DAY(datetime_instance) | Returns the day component of a Date, Datetime |
MONTH(date_instance) <br>MONTH(datetime_instance) | Returns the month component of a Date, Datetime |
YEAR(date_instance) <br>YEAR(datetime_instance) | Returns the year component of a Date, Datetime |
NOW() | Returns the current Datetime based on a GMT calendar |
TODAY() | Returns the current date in the current user’s time zone. |
EDATE(start_date, months) | Add month to Date, Datime |
WEEKDAY(date_instance) | Returns the day of the week corresponding to a date. The day is given as an integer, ranging from 1 (Sunday) to 7 (Saturday) |
WEEKNUM(date_instance) | Returns the week number of a specific date. For example, the week containing January 1 is the first week of the year, and is numbered week 1 |
WORKDAY(start_date_instance, days) | Returns a number that represents a date that is the indicated number of working days before or after a date (the starting date). |
NETWORKDAYS(start_date_instance, end_date_instance) | Returns the number of whole workdays between two dates |
EOMONTH(start_date_instance, months) | Calculates the last day of the month after adding a specified number of months to a date, datetime |
DATEDIFF(start_date, end_date, unit) | Calculates the number of days, months, or years between two dates. |
DAYS(end_date, start_date) | Returns the number of days between two dates |
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.1 is compatible. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.1
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
1.0.0 | 363 | 8/16/2022 |