In the process of project development , You just need to use the processing scenario of evaluating string expressions , So I looked for several qualified third-party components LambdaParser、DynamicExpresso、Z.Expressions, They have different functions , But they can basically meet the requirements . Both of them can evaluate string expressions according to related parameters , This essay introduces the use code of the three , And sum up some of the experience .

Evaluation of mathematical expressions should be the most common , Generally, if we need to calculate in the application , It is necessary to type the parameter , And then perform corresponding calculation in the background . But if you are calculating some formulas or formulas that match , Especially when the parameters are not certain , This is more troublesome . Leverage third-party components , Quick evaluation of expressions , It can meet many of our actual project needs , And it's easy to handle .

These third-party components , Their GitHub Or official website address :

https://github.com/nreco/lambdaparser

https://github.com/dynamicexpresso/DynamicExpresso

https://eval-expression.net/eval-execute

however Z.Expressions Is the charge , The first two are free .

The scenario where I use string expressions to evaluate , The main idea is to SQL Conditional expression , Convert to a normal string expression , Then according to the parameter value of the object , Perform evaluation processing , These expression evaluation components support such operations , In order to better demonstrate their use effect and code , We created a case code to test and verify , Confirm to meet my actual needs .

1、Z.Expressions.Eval Expression parsing

Z.Expression.Eval It's a free and open source ( Follow up charges ), Extensible , Ultra lightweight formulaic language parsing and execution toolkit , Can be resolved at run time C# An open source free component of expressions .Z.Expressions from 2.0 Started to support NetCore, But for a fee . Reference address :https://riptutorial.com/eval-expression/learn/100000/getting-started perhaps https://eval-expression.net/eval-execute.

Parse at run time C# expression , For example, some salary or cost accounting systems , You need to dynamically configure the calculation expression in the background , So as to calculate and evaluate .

The following describes several different case codes and verifies the output results

Anonymous type handling

// Anonymous types 
string expression = "a*2 + b*3 - 3";
int result = Eval.Execute<int>(expression, new { a = 10, b = 5 });
Console.WriteLine("{0} = {1}", expression, result); //a*2 + b*3 - 3 = 32

Specify the parameters

// Specify the parameters 
expression = "{0}*2 + {1}*3 - 3";
result = Eval.Execute<int>(expression, 10, 5);
Console.WriteLine("{0} = {1}", expression, result);//{0}*2 + {1}*3 - 3 = 32

Class object

// Class object 
expression = "a*2 + b*3 - 3";
dynamic expandoObject = new ExpandoObject();
expandoObject.a = 10;
expandoObject.b = 5; result = Eval.Execute<int>(expression, expandoObject);
Console.WriteLine("{0} = {1}", expression, result); //a*2 + b*3 - 3 = 32

A dictionary object

// A dictionary object 
expression = "a*2 + b*3 - 3";
var values = new Dictionary<string, object>()
{
{ "a", 10 },
{ "b", 5 }
}; result = Eval.Execute<int>(expression, values);
Console.WriteLine("{0} = {1}", expression, result);//a*2 + b*3 - 3 = 32

Delegate type

// Delegate type 1
expression = "{0}*2 + {1}*3";
var compiled = Eval.Compile<Func<int, int, int>>(expression);
result = compiled(10, 15);
Console.WriteLine("{0} = {1}", expression, result);//{0}*2 + {1}*3 = 65 // Delegate type 2
expression = "a*2 + b*3";
compiled = Eval.Compile<Func<int, int, int>>(expression, "a", "b");
result = compiled(10, 15);
Console.WriteLine("{0} = {1}", expression, result);//a*2 + b*3 = 65

String extension support

// String extension support - Anonymous types 
expression = "a*2 + b*3 - 3";
result = expression.Execute<int>(new { a = 10, b = 5 });
Console.WriteLine("{0} = {1}", expression, result);//a*2 + b*3 - 3 = 32 // String extension support - Dictionary type
expression = "a*2 + b*3 - 3";
values = new Dictionary<string, object>()
{
{ "a", 10 },
{ "b", 5 }
};
result = expression.Execute<int>(values);
Console.WriteLine("{0} = {1}", expression, result);//a*2 + b*3 - 3 = 32

It can be seen that , This component provides very rich expression operation and evaluation processing methods .

2、NReco.LambdaParser Expression parsing

I like the handling of this component , The main reason is that it can pass in the dictionary type , In this way, I can easily pass in various types of parameters , And this component is close to SQL grammar , You can set up to use the regular = Instead of expression ==, So for SQL Statement is convenient .

Its case code is as follows .

/// <summary>
/// NReco.LambdaParser Expression parsing
/// </summary>
private void btnLamdaParser_Click(object sender, EventArgs e)
{
var lambdaParser = new NReco.Linq.LambdaParser(); var dict = new Dictionary<string, object>();
dict["pi"] = 3.14M;
dict["one"] = 1M;
dict["two"] = 2M;
dict["test"] = "test";
Console.WriteLine(lambdaParser.Eval("pi>one && 0<one ? (1+8)/3+1*two : 0", dict)); // --> 5
Console.WriteLine(lambdaParser.Eval("test.ToUpper()", dict)); // --> TEST Console.WriteLine(lambdaParser.Eval("pi>one && 0<one ", dict)); // --> True
Console.WriteLine(lambdaParser.Eval("test.ToUpper()", dict)); // --> TEST
}

It also supports arithmetic symbol operations such as :+, -, *, /, %, And conventional logical judgment :==, !=, >, <, >=, <=, If necessary, it allows you to = As == Compare , Then set the properties  AllowSingleEqualSign  = true that will do , The following code .

    var lambdaParser = new LambdaParser();
lambdaParser.AllowSingleEqualSign = true;// have access to = As a logical judgment , Such as Title ="Leader", without Title =="Leader"
var evalResult = lambdaParser.Eval(repalce, dict);

This component does not provide too many examples , But its examples provide key points , Basically, it can meet our actual expression evaluation processing requirements .

3、DynamicExpresso Expression parsing

be relative to LambdaParser The concise 、Z.Expressions Charge processing ,Dynamic Expresso  It can be said to provide a very powerful 、 Free and open source processing class library , It provides many ways to implement expression evaluation .

A simple string expression evaluates to the following code

var interpreter = new Interpreter();
var result = interpreter.Eval("8 / 2 + 2");

But generally, we need to pass in certain parameters for expression evaluation .

var target = new Interpreter();
double result = target.Eval<double>("Math.Pow(x, y) + 5",
new Parameter("x", typeof(double), 10),
new Parameter("y", typeof(double), 2));

perhaps

var interpreter = new Interpreter();
var parameters = new[] {
new Parameter("x", 23),
new Parameter("y", 7)
};
Assert.AreEqual(30, interpreter.Eval("x + y", parameters));

Or assign a specified parameter

var target = new Interpreter().SetVariable("myVar", 23);
Assert.AreEqual(23, target.Eval("myVar"));

Dealing with dictionary types , It's the way I like , Its case code is as follows .

var interpreter = new Interpreter();
var dict = new Dictionary<string, object>();
dict.Add("a", 1.0);
dict.Add("b", 2);
dict.Add("d", 4);
dict.Add("e", 5);
dict.Add("str", 'f'); foreach (var v in dict)
{
object value = v.Value;
int para = 0;
if (int.TryParse(v.Value.ToString(), out para))
{
value = (float)para;
}
interpreter.SetVariable(v.Key, value);
}
Console.WriteLine(interpreter.Eval("a+b").ToString()); //3
Console.WriteLine(interpreter.Eval("a/b").ToString()); //0.5
Console.WriteLine(interpreter.Eval("a > b").ToString()); //False
Console.WriteLine(interpreter.Eval("str == 'f'").ToString()); //True

For class attribute expression query , The test code is as follows

    var customers = new List<Customer> {
new Customer() { Name = "David", Age = 31, Gender = 'M' },
new Customer() { Name = "Mary", Age = 29, Gender = 'F' },
new Customer() { Name = "Jack", Age = 2, Gender = 'M' },
new Customer() { Name = "Marta", Age = 1, Gender = 'F' },
new Customer() { Name = "Moses", Age = 120, Gender = 'M' },
};
string whereExpression = "customer.Age > 18 && customer.Gender == 'F'"; Func<Customer, bool> dynamicWhere = interpreter.ParseAsDelegate<Func<Customer, bool>>(whereExpression, "customer");
Console.WriteLine(customers.Where(dynamicWhere).Count());//=> 1 var customer_query = (new List<Customer> {
new Customer() { Name = "David", Age = 31, Gender = 'M' },
new Customer() { Name = "Mary", Age = 29, Gender = 'F' },
new Customer() { Name = "Jack", Age = 2, Gender = 'M' },
new Customer() { Name = "Marta", Age = 1, Gender = 'F' },
new Customer() { Name = "Moses", Age = 120, Gender = 'M' },
}).AsQueryable();
whereExpression = "customer.Age > 18 && customer.Gender == 'F'"; var expression = interpreter.ParseAsExpression<Func<Customer, bool>>(whereExpression, "customer");
Console.WriteLine(customer_query.Where(expression).Count());//=> 1

4、SQL Regular expression and string evaluation processing of conditional statements

We introduced several components of expression evaluation processing , They can basically meet the actual evaluation processing , Only the functions provided are emphasized .

I mainly want to use it to evaluate Boolean values of specific expressions , Judge whether the expression satisfies the condition .

For example, for sql Conditional statements :(Amount> 500 and Title ='Leader') or Age> 32, And a set of parameters of the dictionary object , I hope to be able to extract the Amount、Title、Leader、Age Such a key , Then assign values to the dictionary , To determine the value of the expression .

because sql Expression and C# The expression logic syntax of the code is different , We need to replace and Or For practical && || character , So given a replacement regular expression :\sand|\sor

And I need to extract the key value content of the conditional statement first , Then get the specified key parameters , Then you should also provide a regular expression :\w*[^>=<!'()\s] , This regular expression is mainly used to extract specific character matches .

Extracted content C# The code logic is as follows .

        private void btnRegexExtract_Click(object sender, EventArgs e)
{
var source = this.txtSource.Text; // Replace part of the content first \sand|\sor
source = Regex.Replace(source, this.txtReplaceRegex.Text, "");// Replace expression
// Add a line of record main content
this.txtContent.Text += " Replace the contents after regular expression :";
this.txtContent.AppendText(Environment.NewLine);
this.txtContent.Text += source;
this.txtContent.AppendText(Environment.NewLine); // In matching content processing
var regex = new Regex(this.txtRegex.Text);
var matches = regex.Matches(source); // Traversal to get each matching content
var fieldList = new List<string>();
int i = 0;
foreach (Match match in matches)
{
this.txtContent.AppendText(match.Value);
this.txtContent.AppendText(Environment.NewLine);
if (i++ % 2 == 0)
{
fieldList.Add(match.Value);
}
}
this.txtContent.AppendText(" Get the expression Key :");
this.txtContent.AppendText(Environment.NewLine);
this.txtContent.AppendText(fieldList.ToJson());
this.txtContent.AppendText(Environment.NewLine); var repalce = ReplaceExpress(this.txtSource.Text);
this.txtContent.AppendText(" Replace And=>&& or=>|| '=> \" After the operator :");
this.txtContent.AppendText(Environment.NewLine);
this.txtContent.AppendText(repalce);
}
        /// <summary>
/// Replace And=>&& or=>|| '=> \" After the operator
/// </summary>
/// <param name="source"></param>
/// <returns></returns>
private string ReplaceExpress(string source)
{
// Operator replacement expression
var repalce = Regex.Replace(source, @"\sand\s", " && "); //and => &&
repalce = Regex.Replace(repalce, @"\sor\s", " || "); //or => ||
repalce = Regex.Replace(repalce, @"'", "\""); //'=> \" return repalce;
}

The result of expression processing is as follows

Its logic code is as follows .

        private void btnRunExpression_Click(object sender, EventArgs e)
{
// Operator replacement expression
var repalce = ReplaceExpress(this.txtSource.Text);
this.txtContent.Text = " Replace And=>&& or=>|| '=> \" After the operator :";
this.txtContent.AppendText(Environment.NewLine);
this.txtContent.Text += repalce;
this.txtContent.AppendText(Environment.NewLine);
this.txtContent.AppendText(Environment.NewLine); //(Amount> 500 and Title ='Leader') or Age> 32
var dict = new Dictionary<string, object>();
dict["Amount"] = 600;
dict["Title"] = "Leader";
dict["Age"] = 40; this.txtContent.AppendText(" Dictionary content ");
foreach(var key in dict.Keys)
{
this.txtContent.AppendText($"{key}:{dict[key]} ");
}
this.txtContent.AppendText(Environment.NewLine);
this.txtContent.AppendText(Environment.NewLine); //var valComparer = new ValueComparer() { NullComparison = ValueComparer.NullComparisonMode.Sql };
//var lambdaParser = new LambdaParser(valComparer);
var lambdaParser = new LambdaParser();
lambdaParser.AllowSingleEqualSign = true;// have access to = As a judgment , Such as Title ="Leader", without Title =="Leader"
var express1 = "(Amount> 500 && Title = \"Leader\") or Age>30";
var result1 = lambdaParser.Eval(express1, dict);
this.txtContent.AppendText("LambdaParser Expression processing :");
this.txtContent.AppendText(Environment.NewLine);
this.txtContent.AppendText(express1 + " => " + result1); var express2 = "( Amount> 500 && Title =\"leader\" )"; // String comparison (''=> "")
var result2 = lambdaParser.Eval(express2, dict);
this.txtContent.AppendText(Environment.NewLine);
this.txtContent.AppendText(express2 + " => " + result2); var express3 = "Amount> 500";
var result3 = lambdaParser.Eval(express3, dict);
this.txtContent.AppendText(Environment.NewLine);
this.txtContent.AppendText(express3 + " => " + result3); var express4 = "Title = \"Leader\" "; // String comparison (''=> "")
var result4 = lambdaParser.Eval(express4, dict);
this.txtContent.AppendText(Environment.NewLine);
this.txtContent.AppendText(express4 + " => " + result4); this.txtContent.AppendText(Environment.NewLine);
Console.WriteLine(lambdaParser.Eval("Title.ToString()", dict)); // --> Leader //DynamicExpresso Expression parsing processing
this.txtContent.AppendText(Environment.NewLine);
this.txtContent.AppendText(Environment.NewLine);
this.txtContent.AppendText("DynamicExpresso Expression parsing processing :"); var interpreter = new Interpreter();
foreach (var v in dict)
{
interpreter.SetVariable(v.Key, v.Value);
}
//express3 = "Amount> 500";
var result33 = interpreter.Eval(express3);
this.txtContent.AppendText(Environment.NewLine);
this.txtContent.AppendText(express3 + " => " + result33); // Use '' error , String comparison requires ""
try
{
express4 = "Title == \"Leader\" ";
var result44 = interpreter.Eval(express4);
this.txtContent.AppendText(Environment.NewLine);
this.txtContent.AppendText(express4 + " => " + result44);
}
catch(Exception ex)
{
this.txtContent.AppendText(Environment.NewLine);
this.txtContent.AppendText(express4 + ", Parsing error => " + ex.Message);
} //var dict = new Dictionary<string, object>();
//dict["Amount"] = 600;
//dict["Title"] = "Leader";
//dict["Age"] = 40;
this.txtContent.AppendText(Environment.NewLine);
this.txtContent.AppendText(Environment.NewLine);
this.txtContent.AppendText("Z.Expressions.Eval Expression parsing :");
var result333 = express3.Execute<bool>(dict);
this.txtContent.AppendText(Environment.NewLine);
this.txtContent.AppendText(express3 + " => " + result333); express4 = "Title == 'Leader'"; //Z.Expressions Acceptable ' Instead of "
var result444 = express4.Execute<bool>(dict);
this.txtContent.AppendText(Environment.NewLine);
this.txtContent.AppendText(express4 + " => " + result444);
}

So we can convert SQL The conditional expression is actual C# expression , And assign parameters , Implementation of dynamic expression evaluation processing .

stay C# Third party components are used in development LambdaParser、DynamicExpresso、Z.Expressions, Realize dynamic parsing / More articles on evaluating string expressions

  1. [ turn ] Page tour development Python Components and patterns Presentation Transcript

    turn : Page tour development Python Components and patterns Presentation Transcript 1. Page tour development Python Components and patterns Lai Yonghao ( http://laiyonghao.com ) 20 ...

  2. XCode and Cocoa Using third parties in development dylib Example

    XCode and Cocoa Using third parties in development dylib Example www.educity.cn    Publisher :yukowang    source : Network reprint     Release date :2014 year 06 month 13 Japan      XCode and Co ...

  3. vue Modifying the style of third-party components in does not cause pollution

    vue Reference to third-party components , The style of the third-party component needs to be modified locally in the component , And don't want to get rid of scoped Attributes cause style pollution between components . Only through >>>, through scoped. however , stay sass in ...

  4. laravel Introduction in composer Installed in the vendor Third party components in

    One . Install third party components Method 1 : Use the command line to install the third party ( has phpword For example ): composer require phpoffce/phpword ^v0..* Method 2 : Modify the main project composer.js ...

  5. vue Modifying the style of third-party components in does not take effect

    problem In the use of element-ui when , Sometimes you want to change the style in a component , But it didn't succeed , for example <div class="test"> <el-button> Button </e ...

  6. Android Application development , Third party integration Sina Weibo (sinaWeiboSDK) Process record of

    As a android Developer , It is inevitable to learn to use and integrate third parties API The ability of Sina Weibo is now the most important news express media , It's very common , And provides a more detailed API Access method , So choose integration sinaWeibiS ...

  7. iPhone and iPad Of ios In development utilize WebViewJavascriptBridge Components , adopt UIWebView Yes Html Two way communication

    This article is reprinted to  http://blog.csdn.net/remote_roamer/article/details/7261490 WebViewJavascriptBridge Project Official website http ...

  8. Android Records of problems encountered in importing third-party libraries during development

    1. The problem of repeated circular dependencies (1) demand As shown in the figure below : stay Android In the project , Using modular development , One is the main runner application--Mudule A, The other is library--Library B 1)M ...

  9. iOS The use and configuration of third-party library in development -GDataXML

    The purpose of this article is to find out in time when you need it in the future , You don't have to go every time baidu. 1. xml Parsing library -GDataXML  Reference article :http://blog.csdn.net/tangren03/article/det ...

  10. android app Common components in development

    1 Activity 1.1 Activity Start of First of all ,android manifest The master specified in activity, Click on app Of icon Activate access . second , Use intent, On the other side activit ...

Random recommendation

  1. SQL Server 2008 General paging stored procedures

    1.alert USE [ Database name ] GO /****** Object: StoredProcedure [dbo].[dbTab_PagerHelper] Script Date: 08/22/ ...

  2. Java Threads : Create and launch

    Java Threads : Create and launch One . Define the thread   1. Expand java.lang.Thread class .   There's one of these run() Method , We should pay attention to its usage : public void run() If the thread is independent  R ...

  3. OC Object oriented features : encapsulation

    Conceptual knowledge  1.c Language is process oriented programming : Analyze the steps to solve the problem , Implementation function , In turn, calls  2.oc Language is object-oriented programming : The object of analyzing the composition of the problem , Coordinate the contact and communication between objects , solve the problem  3.#include and #impo ...

  4. mybatis Source code analysis (3)——SqlSessionManager class

    As can be seen from the above figure , stay  mybatis in ,SqlSession There are two implementation classes for , among SqlSessionManager Class not only implements SqlSession Interface , At the same time SqlSessionFactory Interface ...

  5. A complete springmvc + ajaxfileupload The case of asynchronous uploading of pictures

    One , principle See this article for detailed principles springmvc + ajaxfileupload solve ajax Unable to upload pictures asynchronously .java.lang.ClassCastException: org.apache ...

  6. mysql Loop insert data

    In the experiment, we often encounter the situation that more than one piece of data is required, so we think of using SQL Statement loop generates data DROP PROCEDURE if EXISTS test_insert; DELIMITER ;; CREATE PROCEDUR ...

  7. vuex Directly modifying state And use dispatch/commit To modify the state The difference of

    One . Use vuex modify state when , There are two ways : 1. You can use it directly this.$store.state. Variable = xxx; 2.this.$store.dispatch(actionType, pay ...

  8. C++ With the help of curses Library to achieve Tetris

    The main functions are as follows : Block movement control . Cube deformation . Determine whether the blocks touch the boundary and stack the blocks . Remove the blocks . 1. The movement control of the square is up, down, left and right --> deformation , Next --> Accelerated descent , Left --> towards the left ...

  9. 1、mysql First time to know

    Before, when we need to access information when writing code, we used files, but using files to access data is very limited , Today we will enter a new world mysql Film navigation : Database origin Database Overview mysql Introduce Download and install mysql Software basic management First time to know sql ...

  10. Android In depth source code analysis and understanding Aidl Overall call process ( Thunder storm )

    2017 The first day of work in . I don't want to work anymore , The holiday felt like it was over before it started , alas , Time is like this , The new year has begun , Although very reluctant to do business , Can't , It must be done . Because the road behind is still very long , It's still a long way from sixty . I just went to work ...