最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#使用第三方組件實現(xiàn)動態(tài)解析和求值字符串表達式

 更新時間:2022年06月22日 14:38:00   作者:伍華聰  
這篇文章主要介紹了C#如何使用第三方組件(LambdaParser、DynamicExpresso、Z.Expressions)實現(xiàn)動態(tài)解析和求值字符串表達式,感興趣的小伙伴可以跟隨小編一起了解一下

介紹

在進行項目開發(fā)的時候,剛好需要用到對字符串表達式進行求值的處理場景,因此尋找了幾個符合要求的第三方組件LambdaParser、DynamicExpresso、Z.Expressions,它們各自功能有所不同,不過基本上都能滿足要求。它們都可以根據(jù)相關(guān)的參數(shù)進行字符串表達式的求值,本篇隨筆介紹它們?nèi)叩氖褂么a,以及總結(jié)其中的一些經(jīng)驗。

數(shù)學(xué)表達式求值應(yīng)該是最常見的,一般我們在應(yīng)用程序中如果需要計算,是需要對參數(shù)進行類型轉(zhuǎn)換,然后在后臺進行相應(yīng)計算的。但是如果是計算一些符合的式子或者公式,特別是參數(shù)不一定的情況下,這個就比較麻煩。利用第三方組件,對表達式進行快速求值,可以滿足我們很多實際項目上的需求,而且處理起來也很方便。

這幾個第三方組件,它們的GitHub或官網(wǎng)地址:

https://github.com/nreco/lambdaparser

https://github.com/dynamicexpresso/DynamicExpresso 

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

不過Z.Expressions是收費的,前兩者都是免費的。

我使用字符串表達式進行求值的場景,主要就是想對一個SQL條件的表達式,轉(zhuǎn)換為普通的字符串表達式,然后根據(jù)對象的參數(shù)值,進行求值處理,這幾個表達式求值組件都支持這樣的操作,為了更好演示它們的使用效果及代碼,我們專門創(chuàng)建了一個案例代碼進行測試驗證,確認(rèn)滿足我的實際需求。

1、Z.Expressions.Eval 表達式解析

Z.Expression.Eval是一個免費開源的(后續(xù)收費了),可擴展的,超輕量級的公式化語言解析執(zhí)行工具包,可以在運行時解析C#表達式的開源免費組件。Z.Expressions從2.0開始支持了NetCore,但是收費的。參考地址:https://riptutorial.com/eval-expression/learn/100000/getting-started 或者 https://eval-expression.net/eval-execute。

在運行時解析C#表達式,例如一些工資或者成本核算系統(tǒng),就需要在后臺動態(tài)配置計算表達式,從而進行計算求值。

下面對幾個不同的案例代碼進行介紹及輸出結(jié)果驗證

匿名類型處理

//匿名類型
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

指定參數(shù)

//指定參數(shù)
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

類對象

//類對象
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

字典對象

//字典對象
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

委托類型

//委托類型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

//委托類型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

字符串?dāng)U展支持

//字符串?dāng)U展支持-匿名類型
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

//字符串?dāng)U展支持-字典類型
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

可以看出,該組件提供了非常豐富的表達式運算求值處理方式。

2、NReco.LambdaParser 表達式解析

我看中這個組件的處理,主要是因為它能夠傳入?yún)?shù)是字典類型,這樣我可以非常方便的傳入各種類型的參數(shù),并且這個組件比較接近SQL語法,可以設(shè)置利用常規(guī)的=代替表達式的==,這樣對于SQL語句來說是方便的。

它的案例代碼如下所示。

/// <summary>
/// NReco.LambdaParser 表達式解析
/// </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
}

同樣它支持的算術(shù)符號操作有:+, -, *, /, %,以及常規(guī)的邏輯判斷:==, !=, >, <, >=, <=,如果需要它允許把=作為==比較,那么設(shè)置屬性 AllowSingleEqualSign  = true 即可,如下代碼。

var lambdaParser = new LambdaParser();
    lambdaParser.AllowSingleEqualSign = true;//可以使用 = 作為邏輯判斷,如Title ="Leader",而不用Title =="Leader"
    var evalResult = lambdaParser.Eval(repalce, dict);

該組件沒有過多提供例子,不過它的例子提供的關(guān)鍵點,基本上都能實現(xiàn)我們實際的表達式求值處理要求了。 

3、DynamicExpresso 表達式解析

相對于LambdaParser的簡潔、Z.Expressions收費處理,Dynamic Expresso 可以說是提供了一個非常強大的、免費開源的處理類庫,它提供非常多的表達式求值的實現(xiàn)方式。

簡單的字符串表達式求值如下代碼

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

但是一般我們需要傳入一定的參數(shù)進行表達式求值的。

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

或者

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

或者賦值指定的參數(shù)

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

對于字典類型的處理,是我喜歡的方式,它的案例代碼如下所示。

var interpreter = new<strong> Interpreter</strong>();
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

對于類的屬性表達式查詢,測試代碼如下所示

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 = "<strong>customer.Age > 18 && customer.Gender == 'F'</strong>";

    Func<Customer, bool> dynamicWhere = interpreter.ParseAsDelegate<Func<Customer, bool>>(whereExpression, "<strong>customer</strong>");
    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 = "<strong>customer.Age > 18 && customer.Gender == 'F'</strong>";

    var expression = interpreter.ParseAsExpression<Func<Customer, bool>>(whereExpression, "<strong>customer</strong>");
    Console.WriteLine(customer_query.Where(expression).Count());//=> 1

4、SQL條件語句的正則表達式和字符串求值處理

前面介紹了幾個表達式求值處理的組件,他們基本上都能夠滿足實際的求值處理,只是提供的功能有所側(cè)重。

我主要希望用它來對特定的表達式進行求布爾值,判斷表達式是否滿足條件的。

例如對于sql條件語句:(Amount> 500 and Title ='Leader') or Age> 32, 以及一個字典對象的參數(shù)集合,我希望能夠提取里面的Amount、Title、Leader、Age這樣的鍵,然后給字典賦值,從而判斷表達式的值。

由于sql表達式和C#代碼的表達式邏輯語法有所差異,我們需要替換and Or 為實際的&& || 字符,因此給定替換的正則表達式:\sand|\sor

而我需要先提取條件語句的鍵值內(nèi)容,然后獲得指定的鍵參數(shù),那么也要提供一個正則表達式:\w*[^>=<!'()\s] ,這個正則表達式主要就是提取特定的字符匹配。

提取內(nèi)容的C#代碼邏輯如下所示。

private void btnRegexExtract_Click(object sender, EventArgs e)
        {
            var source = this.txtSource.Text;

            //先替換部分內(nèi)容 \sand|\sor
            source = Regex.Replace(source, this.txtReplaceRegex.Text, "");//替換表達式
            //增加一行記錄主內(nèi)容
            this.txtContent.Text += "替換正則表達式后內(nèi)容:";
            this.txtContent.AppendText(Environment.NewLine);
            this.txtContent.Text += source;
            this.txtContent.AppendText(Environment.NewLine);

            //在匹配內(nèi)容處理
            var regex = new Regex(this.txtRegex.Text);
            var matches = regex.Matches(source);

            //遍歷獲得每個匹配的內(nèi)容
            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("獲得表達式鍵:");
            this.txtContent.AppendText(Environment.NewLine);
            this.txtContent.AppendText(fieldList.ToJson());
            this.txtContent.AppendText(Environment.NewLine);

            var repalce = ReplaceExpress(this.txtSource.Text);
            this.txtContent.AppendText("替換And=>&& or=>|| '=> \" 操作符后內(nèi)容:");
            this.txtContent.AppendText(Environment.NewLine);
            this.txtContent.AppendText(repalce);
        }
/// <summary>
        /// 替換And=>&& or=>|| '=> \" 操作符后內(nèi)容
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        private string ReplaceExpress(string source)
        {
            //操作符替換表達式
            var repalce = Regex.Replace(source, @"\sand\s", " && "); //and => &&
            repalce = Regex.Replace(repalce, @"\sor\s", " || "); //or => ||
            repalce = Regex.Replace(repalce, @"'", "\""); //'=> \"

            return repalce;
        }

表達式處理結(jié)果如下所示

它的邏輯代碼如下。

private void btnRunExpression_Click(object sender, EventArgs e)
        {
            //操作符替換表達式
            var repalce = ReplaceExpress(this.txtSource.Text);
            this.txtContent.Text = "替換And=>&& or=>|| '=> \" 操作符后內(nèi)容:";
            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("字典內(nèi)容");
            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;//可以使用=作為判斷,如Title ="Leader",而不用Title =="Leader"
            var express1 = "(Amount> 500 && Title = \"Leader\") or Age>30";
            var result1 = lambdaParser.Eval(express1, dict);
            this.txtContent.AppendText("LambdaParser 表達式處理:");
            this.txtContent.AppendText(Environment.NewLine);
            this.txtContent.AppendText(express1 + " => " + result1);

            var express2 = "( Amount> 500 && Title =\"leader\" )"; //字符串比較(''=> "")
            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\" "; //字符串比較(''=> "")
            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 表達式解析處理
            this.txtContent.AppendText(Environment.NewLine);
            this.txtContent.AppendText(Environment.NewLine);
            this.txtContent.AppendText("DynamicExpresso 表達式解析處理:");

            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);

            //使用''出錯,字符串比較需要使用""
            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 + ",解析出錯 => " + 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 表達式解析:");
            var result333 = express3.Execute<bool>(dict);
            this.txtContent.AppendText(Environment.NewLine);
            this.txtContent.AppendText(express3 + " => " + result333);

            express4 = "Title == 'Leader'"; //Z.Expressions可以接受 ' 代替 "
            var result444 = express4.Execute<bool>(dict);
            this.txtContent.AppendText(Environment.NewLine);
            this.txtContent.AppendText(express4 + " => " + result444);
        }

這樣我們就可以轉(zhuǎn)換SQL條件表達式為實際的C#表達式,并通過賦值參數(shù),實現(xiàn)動態(tài)表達式的求值處理。

到此這篇關(guān)于C#使用第三方組件實現(xiàn)動態(tài)解析和求值字符串表達式的文章就介紹到這了,更多相關(guān)C#解析 求值字符串表達式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Unity繪制二維動態(tài)曲線

    Unity繪制二維動態(tài)曲線

    這篇文章主要為大家詳細(xì)介紹了Unity繪制二維動態(tài)曲線,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-03-03
  • 通過C#實現(xiàn)在Excel單元格中寫入文本、或數(shù)值

    通過C#實現(xiàn)在Excel單元格中寫入文本、或數(shù)值

    在商業(yè)、學(xué)術(shù)和日常生活中,Excel 的使用極為普遍,本文將詳細(xì)介紹如何使用免費.NET庫將數(shù)據(jù)寫入到 Excel 中,包括文本、數(shù)值、數(shù)組、和DataTable數(shù)據(jù)的輸入,需要的朋友可以參考下
    2024-07-07
  • c#調(diào)用jar包的方法步驟(非常詳細(xì))

    c#調(diào)用jar包的方法步驟(非常詳細(xì))

    這篇文章主要給大家介紹了關(guān)于c#調(diào)用jar包的方法步驟,文中通過圖文介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • c#實現(xiàn)sunday算法實例

    c#實現(xiàn)sunday算法實例

    Sunday算法思想跟BM算法很相似,在匹配失敗時關(guān)注的是文本串中參加匹配的最末位字符的下一位字符,下面是用C#實現(xiàn)sunday的實例代碼,有需要的朋友可以參考一下
    2013-08-08
  • C#中的let字句應(yīng)用示例

    C#中的let字句應(yīng)用示例

    這篇文章主要給大家介紹了C#中的let字句,文中通過應(yīng)用實例介紹的很詳細(xì),相信對大家具有一定的參考價值,有需要的朋友們下面來一起看看吧。
    2017-02-02
  • WPF實現(xiàn)3D粒子波浪效果

    WPF實現(xiàn)3D粒子波浪效果

    這篇文章主要為大家詳細(xì)介紹了WPF實現(xiàn)3D粒子波浪效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-09-09
  • List轉(zhuǎn)換成DataSet實現(xiàn)代碼

    List轉(zhuǎn)換成DataSet實現(xiàn)代碼

    怎樣把List轉(zhuǎn)換成DataSet本人很是疑惑,于是搜集整理一番,需要的朋友可以參考下
    2012-12-12
  • c# 委托詳解

    c# 委托詳解

    本文將通過實例解析對c# 委托進行詳細(xì)介紹,具有很好的參考價值,下面跟著小編一起來看下吧
    2017-02-02
  • 在.NET中讀取嵌入和使用資源文件的方法

    在.NET中讀取嵌入和使用資源文件的方法

    本文分別介紹了使用GetManifestResourceStream讀取嵌入資源,和使用. resx資源文件嵌入資源,希望對大家有所幫助。
    2016-05-05
  • 詳解C#如何使用重載方法實現(xiàn)不同類型數(shù)據(jù)的計算

    詳解C#如何使用重載方法實現(xiàn)不同類型數(shù)據(jù)的計算

    這篇文章主要為大家詳細(xì)介紹了C#如何使用重載方法實現(xiàn)不同類型數(shù)據(jù)的計算,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-02-02

最新評論

定西市| 云林县| 大英县| 喀什市| 库车县| 通河县| 方山县| 芦山县| 绵阳市| 驻马店市| 淮北市| 宁陵县| 黑龙江省| 汝州市| 石景山区| 喜德县| 高淳县| 阿克| 呼玛县| 泗洪县| 洛阳市| 马边| 会理县| 郯城县| 灵璧县| 桃江县| 潮州市| 奎屯市| 上饶市| 旬邑县| 江源县| 平南县| 高淳县| 阿合奇县| 马尔康县| 枣庄市| 东辽县| 彰化市| 孟村| 北辰区| 西林县|