NoStringEvaluating 2.3.0
See the version list below for details.
dotnet add package NoStringEvaluating --version 2.3.0
NuGet\Install-Package NoStringEvaluating -Version 2.3.0
<PackageReference Include="NoStringEvaluating" Version="2.3.0" />
paket add NoStringEvaluating --version 2.3.0
#r "nuget: NoStringEvaluating, 2.3.0"
// Install NoStringEvaluating as a Cake Addin #addin nuget:?package=NoStringEvaluating&version=2.3.0 // Install NoStringEvaluating as a Cake Tool #tool nuget:?package=NoStringEvaluating&version=2.3.0
NoStringEvaluating
Fast and easy mathematical evaluation without endless string parsing! Parses string formula once and uses its object sequence in each evaluation. Moreover, provides user defined functions and variables. From v2.0 it can evaluate string, DateTime, etc...
Microsoft.Extensions.DependencyInjection
- Features
- Performance
- Quick start
- Extra types
- Variables
- Operators
- Boolean operators
- Functions
- Options
- Documentation
- TODO
Features
- Fast math evaluation
- Zero-allocation code (object pooling)
- User defined functions
- User defined variables with any chars
- Mixed result type
Performance
Compared with a good solution mXparser
- In general, x7 faster!
Testing formulas
№ | Formula |
---|---|
Empty | |
NumberOnly | 3 |
1 | 3 * 9 |
2 | 3 * 9 / 456 * 32 + 12 / 17 - 3 |
3 | 3 * (9 / 456 * (32 + 12)) / 17 - 3 |
4 | (2 + 6 - (13 * 24 + 5 / (123 - 364 + 23))) - (2 + 6 - (13 * 24 + 5 / (123 - 364 + 23))) + (2 + 6 - (13 * 24 + 5 / (123 - 364 + 23))) * 345 * ((897 - 323)/ 23) |
5 | Arg1 * Arg2 + Arg3 - Arg4 |
6 | Arg1 * (Arg2 + Arg3) - Arg4 / (Arg5 - Arg6) + 45 * Arg7 + ((Arg8 * 56 + (12 + Arg9))) - Arg10 |
7 | add(1; 2; 3) |
8 | add(add(5; 1) - add(5; 2; 3)) |
9 | if(Arg1; add(56 + 9 / 12 * 123.596; or(78; 9; 5; 2; 4; 5; 8; 7); 45;5); 9) * 24 + 52 -33 |
10 | kov(1; 2; 3) - kovt(8; 9) |
1 000 000 calculations
Less is better
Benchmark results
NoStringEvaluator
MxParser
Both
Conclusion
As you can see, this solution faster in all cases, what's more, there isn't any garbage collection.
Benchmark code you can find in ConsoleApp.Benchmark.BenchmarkNumberService.
Benchmark excel sheet you can find here - BenchResults.Benchmark.xlsx.
Quick start
Initializing
Basically, this solution has developed for web api projects, so you should add implementations in Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
// ......
services.AddNoStringEvaluator();
}
Usage
Add INoStringEvaluator to your controller, service, etc...
And just send string or FormulaNodes to evaluation:
public class MyService
{
private INoStringEvaluator _noStringEvaluator;
public MyService(INoStringEvaluator noStringEvaluator)
{
_noStringEvaluator = noStringEvaluator;
}
public double CalcNumber(string formula)
{
return _noStringEvaluator.CalcNumber(formula);
}
public string CalcWord(string formula)
{
return _noStringEvaluator.CalcWord(formula);
}
public EvaluatorValue Calc(string formula)
{
return _noStringEvaluator.Calc(formula);
}
}
If you have variables, you can send IDictionary or your IVariablesContainer implementation:
public class MyService
{
private INoStringEvaluator _noStringEvaluator;
public MyService(INoStringEvaluator noStringEvaluator)
{
_noStringEvaluator = noStringEvaluator;
}
public double Calc(string formula, IDictionary<string, EvaluatorValue> variables)
{
return _noStringEvaluator.CalcNumber(formula, variables);
}
}
User defined functions
If you need your function, just implement the interface IFunction
If you want to returnt extra type, use factory.
For instance, usage function "YouAre('Vitaly'; 26)":
public class MyFunction : IFunction
{
public string Name { get; } = "YouAre";
public InternalEvaluatorValue Execute(List<InternalEvaluatorValue> args, ValueFactory factory)
{
var name = args[0].GetWord();
var age = args[1];
var ageAfterDecade = age + 10;
var result = $"Hello, {name}. After 10 years you will be {ageAfterDecade} y.o.";
return factory.Word().Create(result);
}
}
And don't forget to add this function to IFunctionReader
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// ...
var functionReader = app.ApplicationServices.GetRequiredService<IFunctionReader>();
functionReader.AddFunction(new MyFunction());
// If you don't want to write the each function directly, use this:
// Just send type from assembly where you have functions
// NoStringFunctionsInitializer.InitializeFunctions(functionReader, typeof(Startup));
}
Extra types
From v2.0 you can evaluate some of types. I strongly recommend, if you know a function's result type, use method kinda CalcNumber or CalcWord. For case if you have no idea about a result's type, use Calc. It returns struct with aggregated types. Just look at property TypeKey and you'll know about a type.
List description
From v2.1 you can describe a list inside the formula
Example | Result |
---|---|
IsMember({'printer', 'computer', 'monitor'}; 'computer') | 1 |
Unique({'NEW','OLD','NEW','HEAVEN','OLD'}) | {'NEW','OLD','HEAVEN'} |
Add({1, 2, 3, 10, 3}) | 19 |
Variables
You can use two types of variables:
- Simple variable
- Bordered variable
Simple variable
Simple variable means that it named without unique symbols and starts with a letter. Only one extra symbol is possible, it's "_"
Some examples:
- "25 + myArgument - 1"
- "25 + myArg1 - 2"
- "arg5684argArg_arg"
- "25 + myArgument_newAge - 3"
Bordered variable
Bordered variable means that it has a difficult name with any symbols, except for square brackets.
Some examples:
- "25 + [myVariable and some words] - 1"
- "25 + [Provider("my provider").Month(1).Price] - 2"
- "[myVariable ♥]"
- "[simpleVariable]"
Needless to say, you can write simple variable with brackets as well.
Precompiled variables
There are some known variables, you shouldn't send them to Calc method.
Key word | Description | Value |
---|---|---|
pi | Pi, Archimedes' constant or Ludolph's number | 3.14159265358979323846 |
tau | A circle constant equal to 2π | 6.283185307179586476925 |
e | Napier's constant, or Euler's number, base of Natural logarithm | 2.7182818284590452354 |
true | Boolean True represented as double | 1 |
false | Boolean False represented as double | 0 |
ASC | Boolean True represented as double | 1 |
DESC | Boolean False represented as double | 0 |
These variables are register independent, you can write Pi, [PI], pI, True, etc...
Operators
Key word | Description | Example |
---|---|---|
+ | Addition | a + b |
- | Subtraction | a - b |
* | Multiplication | a * b |
/ | Division | a / b |
^ | Exponentiation | a^b |
Boolean operators
Key word | Description | Example |
---|---|---|
< | Lower than | a < b |
⇐ | Lower or equal | a ⇐ b |
> | Greater than | a > b |
>= | Greater or equal | a >= b |
== | Equality | a == b |
!= | Inequation | a != b |
&& | Logical conjunction (AND) | a && b |
|| | Logical disjunction (OR) | a || b |
Functions
Math
Key word | Description | Example |
---|---|---|
add | Summation operator | add(a1; a2; ...; an) can include List<double> |
multi | Multiplication | multi(a1; a2; ...; an) can include List<double> |
mean | Mean / average value | mean(a1; a2; ...; an) can include List<double> |
min | Minimum function | min(a; b) can include List<double> |
max | Maximum function | max(a; b) can include List<double> |
Rpund | Rounds the designated number to the specified decimals | Round(a; decimals) |
ln | Natural logarithm function (base e) | ln(x) |
log | Logarithm function (base b) | log(a; b) |
log2 | Binary logarithm function (base 2) | log2(x) |
log10 | Common logarithm function (base 10) | log10(x) |
sqrt | Squre root function | sqrt(x) |
abs | Absolut value function | abs(x) |
sgn | Signum function | sgn(x) |
sign | Signum function | sign(x) |
floor | Floor function | floor(x) |
ceil | Ceiling function | ceil(x) |
mod | Modulo function | mod(a; b) |
fact | Factorial function | fact(x) |
fib | Fibonacci number | fib(x) |
gcd | Greatest common divisor | gcd(a1; a2; ...; an) |
lcm | Least common multiple | lcm(a1; a2; ...; an) |
Trigonometry
Key word | Description | Example |
---|---|---|
sin | Trigonometric sine function | sin(x) |
cos | Trigonometric cosine function | cos(x) |
tg | Trigonometric tangent function | tg(x) |
tan | Trigonometric tangent function | tan(x) |
ctg | Trigonometric cotangent function | ctg(x) |
cot | Trigonometric cotangent function | cot(x) |
ctan | Trigonometric cotangent function | ctan(x) |
sec | Trigonometric secant function | sec(x) |
csc | Trigonometric cosecant function | csc(x) |
cosec | Trigonometric cosecant function | cosec(x) |
asin | Inverse trigonometric sine function | asin(x) |
arsin | Inverse trigonometric sine function | arsin(x) |
arcsin | Inverse trigonometric sine function | arcsin(x) |
acos | Inverse trigonometric cosine function | acos(x) |
arcos | Inverse trigonometric cosine function | arcos(x) |
arccos | Inverse trigonometric cosine function | arccos(x) |
atg | Inverse trigonometric tangent function | atg(x) |
atan | Inverse trigonometric tangent function | atan(x) |
arctg | Inverse trigonometric tangent function | arctg(x) |
arctan | Inverse trigonometric tangent function | arctan(x) |
actg | Inverse trigonometric cotangent function | actg(x) |
acot | Inverse trigonometric cotangent function | acot(x) |
actan | Inverse trigonometric cotangent function | actan(x) |
arcctg | Inverse trigonometric cotangent function | arcctg(x) |
arccot | Inverse trigonometric cotangent function | arccot(x) |
arcctan | Inverse trigonometric cotangent function | arcctan(x) |
sinh | Hyperbolic sine function | sinh(x) |
cosh | Hyperbolic cosine function | cosh(x) |
tgh | Hyperbolic tangent function | tgh(x) |
tanh | Hyperbolic tangent function | tanh(x) |
coth | Hyperbolic cotangent function | coth(x) |
ctgh | Hyperbolic cotangent function | ctgh(x) |
ctanh | Hyperbolic cotangent function | ctanh(x) |
sech | Hyperbolic secant function | sech(x) |
csch | Hyperbolic cosecant function | csch(x) |
cosech | Hyperbolic cosecant function | cosech(x) |
arcsec | Inverse trigonometric secant | arcsec(x) |
asinh | Inverse hyperbolic sine function | asinh(x) |
arsinh | Inverse hyperbolic sine function | arsinh(x) |
arcsinh | Inverse hyperbolic sine function | arcsinh(x) |
acosh | Inverse hyperbolic cosine function | acosh(x) |
arcosh | Inverse hyperbolic cosine function | arcosh(x) |
arccosh | Inverse hyperbolic cosine function | arccosh(x) |
atgh | Inverse hyperbolic tangent function | atgh(x) |
atanh | Inverse hyperbolic tangent function | atanh(x) |
arctgh | Inverse hyperbolic tangent function | arctgh(x) |
arctanh | Inverse hyperbolic tangent function | arctanh(x) |
acoth | Inverse hyperbolic cotangent function | acoth(x) |
actgh | Inverse hyperbolic cotangent function | actgh(x) |
actanh | Inverse hyperbolic cotangent function | actanh(x) |
arccoth | Inverse hyperbolic cotangent function | arccoth(x) |
arcctgh | Inverse hyperbolic cotangent function | arcctgh(x) |
arcctanh | Inverse hyperbolic cotangent function | arcctanh(x) |
asech | Inverse hyperbolic secant function | asech(x) |
arsech | Inverse hyperbolic secant function | arsech(x) |
arcsech | Inverse hyperbolic secant function | arcsech(x) |
acsch | Inverse hyperbolic cosecant function | acsch(x) |
arcsch | Inverse hyperbolic cosecant function | arcsch(x) |
arccsch | Inverse hyperbolic cosecant function | arccsch(x) |
acosech | Inverse hyperbolic cosecant function | acosech(x) |
arcosech | Inverse hyperbolic cosecant function | arcosech(x) |
rad | Degrees to radians function | rad(x) |
deg | Radians to degrees function | deg(x) |
exp | Exponential function | exp(x) |
Logic
Key word | Description | Example |
---|---|---|
if | If function | if(cond; expr-if-true; expr-if-false) |
iff | If function | iff( cond-1; expr-1; ... ; cond-n; expr-n ) |
and | Logical conjunction (AND) | and(a1; a2; ...; an) |
or | Logical disjunction (OR) | or(a1; a2; ...; an) |
not | Negation function | not(x) |
IsNaN | Returns true = 1 if value is a Not-a-Number (NaN), false = 0 | isNaN(x) |
IsError | Returns 1 if this is a double.NaN | IsError(ToNumber('Text')) |
IsMember | Checks if second argument is a member of list from first | IsMember({'printer', 'computer', 'monitor'}; 'computer') |
IsNumber | Returns 1 if this is a number | IsNumber(256) |
Excel
I've implemented some of excel functions. If you wanna see more, just send me a message.
Key word | Description | Example |
---|---|---|
Count | Returns a number of elements | Count(a; b; ...) can include List<T> |
Len | Returns the number of characters in a text string | Len("my word") |
Sort | Sorts a List. sortType: 1 - asc, not 1 - desc | Sort(myList; sortType) |
ToNumber | Returns number from word | ToNumber('03') |
DateTime
Key word | Description | Example |
---|---|---|
DateDif | Calculates the number of days, months, or years between two dates. Can be: Y, M, D | DateDif(date1; date2; 'Y') |
TimeDif | Calculates the number of hours, minutes, or seconds between two dates. Can be: H, M, S | DateDif(time1; time2; 'H') |
Now | Returns Datetime.Now | Now() |
Today | Returns the current date | Today() |
Day | Returnts a day from dateTime | Day(Now())<br /> Day(Now(); 'DD') |
Month | Returns a month from dateTime | Month(Now())<br /> Month(Now(); 'MM') |
Year | Returns a year from dateTime | Year(Now())<br /> Year(Now(); 'YY') |
ToDateTime | Returns datetime value from string | ToDateTime('8/15/2002') |
WeekDay | Takes a date and returns a number between 1-7 representing the day of week | WeekDay(Today()) |
DateFormat | Format dateTime to string | DateFormat(Now(); 'HH:mm:ss') |
Word
Key word | Description | Example |
---|---|---|
Concat | Concates values | Concat(56; ' myWord') <br /> Concat(myList; myArg; 45; myList2) |
Explode | Returns a text list composed of the elements of a text string. Separator by default is white space " " | Explode(myWord)<br /> Explode(myWord; separator) |
Implode | Concatenates all members of a text list and returns a text string. separator by default is empty "" | Implode(myList) <br /> Implode(myList; separator) <br /> Implode(myList; 5; 'my wordd'; separator) last value is separator |
Left | Searches a string from left to right and returns the leftmost characters of the string | Left(myWord)<br /> Left(myWord; numberOfChars) <br /> Left(myWord; wordNeededChars) |
Middle | Returns any substring from the middle of a string | Middle(myWord; indexStart; numberChars) <br /> Middle(myWord; indexStart; wordEnd)<br /> Middle(myWord; wordStart; numberChars)<br /> Middle(myWord; wordStart; wordEnd) |
Right | Searches a string from right to left and returns the rightmost characters of the string | Right(myWord)<br /> Right(myWord; numberOfChars)<br /> Right(myWord; wordNeededChars) |
Lower | Converts text to lowercase | Lower(myWord)<br /> Lower(myWordList) |
Upper | Converts text to uppercase | Upper(myWord)<br /> Upper(myWordList) |
Proper | Capitalizes the first letter in each word of a text | Proper(myWord) |
Replace | Replaces characters within text | Replace(myWord; oldPart; newPart) <br /> Replace(myList; oldPart; newPart) |
Text | Returns text from first argument | Text(26) |
Unique | If second parameter is true then returns only qnique If second parameter is false then returns list without doubles | Unique(myList) <br /> Unique(myList; true) |
IsText | Returns 1 if this is a word | IsText('my word') |
Options
When you use AddNoStringEvaluator in startup.cs you can configure evaluator.
There are several options:
- FloatingTolerance (default is 0.0001)
- FloatingPointSymbol (default is FloatingPointSymbol.Dot)
- WordQuotationMark (default is null)
To illustrate, I change floating point from default dot to comma:
public void ConfigureServices(IServiceCollection services)
{
// ......
services.AddNoStringEvaluator(opt => opt.SetFloatingPointSymbol(FloatingPointSymbol.Comma));
}
Documentation
Solution contains five following services:
- IFormulaParser
- IFunctionReader
- IFormulaCache
- IFormulaChecker
- INoStringEvaluator
One optional interface, you can implement if IDictionary is inconvenient.
- IVariablesContainer
Furthermore, three object pools:
ObjectPool.Create<Stack<InternalEvaluatorValue>>
ObjectPool.Create<List<InternalEvaluatorValue>>
ObjectPool.Create<ExtraTypeIdContainer>
IFormulaParser
Performs two functions:
- Parsing from char collection to object sequence
- Reversing sequence as Reverse Polish notation
Contains three methods:
FormulaNodes Parse(string formula)
FormulaNodes Parse(ReadOnlySpan<char> formula)
List<IFormulaNode> ParseWithoutRpn(ReadOnlySpan<char> formula)
IFunctionReader
Performs using user defined functions.
Contains three methods:
void AddFunction(IFunction func, bool replace = false)
void RemoveFunction(string functionName)
bool TryProceedFunction(List<IFormulaNode> nodes, ReadOnlySpan<char> formula, ref int index)
IFormulaCache
Performs formula caching. It is used by default INoStringEvaluator implementation. It uses IFormulaParser which parses string formula to object sequence.
Contains one method:
FormulaNodes GetFormulaNodes(string formula)
IFormulaChecker
Performs syntax checking.
Contains two methods:
CheckFormulaResult CheckSyntax(string formula)
CheckFormulaResult CheckSyntax(ReadOnlySpan<char> formula)
INoStringEvaluator
Performs evaluating ☺️
Contains methods:
double CalcNumber(string formula, IVariablesContainer variables)
double CalcNumber(FormulaNodes formulaNodes, IVariablesContainer variables)
double CalcNumber(string formula, IDictionary<string, EvaluatorValue> variables)
double CalcNumber(FormulaNodes formulaNodes, IDictionary<string, EvaluatorValue> variables)
double CalcNumber(string formula)
double CalcNumber(FormulaNodes formulaNodes)
string CalcWord(...
DateTime CalcDateTime(...
List<string> CalcWordList(...
List<double> CalcNumberList(...
bool CalcBoolean(...
EvaluatorValue Calc(...
TODO
- Add more functions
- Any idea?
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net6.0 is compatible. 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. |
-
net6.0
- Microsoft.Extensions.ObjectPool (>= 6.0.7)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on NoStringEvaluating:
Package | Downloads |
---|---|
Corprio.Core
Shared libraries for developing Corprio applications |
|
NoStringEvaluating.Extensions.Microsoft.DependencyInjection
DI extensions for "Extensions.Microsoft.DependencyInjection" |
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
2.6.0 | 1,619 | 8/24/2024 |
2.5.3 | 1,361 | 8/6/2024 |
2.5.2 | 13,927 | 1/27/2023 |
2.5.1 | 1,025 | 10/27/2022 |
2.5.0 | 641 | 10/7/2022 |
2.4.2 | 624 | 9/17/2022 |
2.4.1 | 2,111 | 8/31/2022 |
2.4.0 | 1,497 | 8/14/2022 |
2.3.0 | 688 | 7/16/2022 |
2.2.2 | 43,943 | 9/26/2021 |
2.2.1 | 518 | 8/21/2021 |
2.2.0 | 461 | 5/29/2021 |
2.1.0 | 407 | 5/10/2021 |
2.0.0 | 424 | 4/20/2021 |
1.4.4 | 632 | 2/19/2021 |
1.4.3 | 432 | 2/6/2021 |
1.4.2 | 431 | 1/30/2021 |
1.4.1 | 416 | 1/24/2021 |
1.4.0 | 453 | 1/16/2021 |
1.3.0 | 464 | 1/9/2021 |
1.2.1 | 420 | 1/7/2021 |
1.2.0 | 447 | 1/7/2021 |
1.1.0 | 445 | 1/5/2021 |
1.0.2 | 521 | 1/2/2021 |
1.0.1 | 468 | 1/1/2021 |
1.0.0 | 506 | 1/1/2021 |
NET6