কোনও স্ট্রিংকে এর সমতুল্য লিনকিউ এক্সপ্রেশন ট্রি তে কীভাবে রূপান্তর করবেন?


173

এটি মূল সমস্যার একটি সরলীকৃত সংস্করণ।

আমার একটি ব্যক্তি নামে একটি ক্লাস রয়েছে:

public class Person {
  public string Name { get; set; }
  public int Age { get; set; }
  public int Weight { get; set; }
  public DateTime FavouriteDay { get; set; }
}

... এবং একটি উদাহরণ বলতে দিন:

var bob = new Person {
  Name = "Bob",
  Age = 30,
  Weight = 213,
  FavouriteDay = '1/1/2000'
}

আমি আমার প্রিয় পাঠ্য সম্পাদকটিতে একটি স্ট্রিং হিসাবে লিখতে চাই ....

(Person.Age > 3 AND Person.Weight > 50) OR Person.Age < 3

আমি এই স্ট্রিংটি এবং আমার অবজেক্টটি ধরতে চাই এবং সত্য বা মিথ্যা মূল্যায়ন করতে চাই - অর্থাত্ বস্তুর উদাহরণে একটি ফানক <ব্যক্তি, বুল> এর মূল্যায়ন।

এখানে আমার বর্তমান চিন্তাভাবনাগুলি:

  1. বেসিক তুলনা এবং লজিকাল অপারেটরদের সমর্থন করতে এএনটিএলআরে একটি বেসিক ব্যাকরণ প্রয়োগ করুন। আমি ভিজ্যুয়াল বেসিক অগ্রাধিকার এবং কিছু ফিচারসেট এখানে অনুলিপি করার কথা ভাবছি: http://msdn.microsoft.com/en-us/library/fw84t893(VS.80).aspx
  2. এএনটিএলআরকে সরবরাহিত স্ট্রিং থেকে উপযুক্ত এএসটি তৈরি করতে হবে।
  3. এএসটি চলুন এবং গতিশীলভাবে ফানক <ব্যক্তি, বুল> তৈরি করতে প্রিডিকেট বিল্ডার কাঠামোটি ব্যবহার করুন
  4. প্রয়োজনীয় হিসাবে ব্যক্তির একটি উদাহরণের বিরুদ্ধে শিকারীর মূল্যায়ন করুন

আমার প্রশ্ন হ'ল আমি কি একেবারে উপচে পড়েছি? কোন বিকল্প?


সম্পাদনা: নির্বাচিত সমাধান

আমি ডাইনামিক লিনক লাইব্রেরিটি ব্যবহার করার সিদ্ধান্ত নিয়েছি, বিশেষত লাইনকিউ নমুনায় প্রদত্ত ডায়নামিক ক্যোয়ারী ক্লাস।

নীচে কোড:

using System;
using System.Linq.Expressions;
using System.Linq.Dynamic;

namespace ExpressionParser
{
  class Program
  {
    public class Person
    {
      public string Name { get; set; }
      public int Age { get; set; }
      public int Weight { get; set; }
      public DateTime FavouriteDay { get; set; }
    }

    static void Main()
    {
      const string exp = @"(Person.Age > 3 AND Person.Weight > 50) OR Person.Age < 3";
      var p = Expression.Parameter(typeof(Person), "Person");
      var e = System.Linq.Dynamic.DynamicExpression.ParseLambda(new[] { p }, null, exp);
      var bob = new Person
      {
        Name = "Bob",
        Age = 30,
        Weight = 213,
        FavouriteDay = new DateTime(2000,1,1)
      };

      var result = e.Compile().DynamicInvoke(bob);
      Console.WriteLine(result);
      Console.ReadKey();
    }
  }
}

ফলাফল টাইপ সিস্টেম.বুলিয়ান, এবং এই উদাহরণে সত্য।

মার্ক গ্র্যাভেলকে অনেক ধন্যবাদ।

এখানে সিস্টেম.লিনক.ডায়নামিক নুগেট প্যাকেজ, ডকুমেন্টেশন অন্তর্ভুক্ত করুন


33
আপনার প্রশ্নের পাশাপাশি সম্পূর্ণ সমাধান কোড পোস্ট করার জন্য ধন্যবাদ। অনেক প্রশংসিত.
অ্যাড্রিয়ান গ্রিগোর

আপনার যদি কোনও সংগ্রহ বা লোক থাকে এবং কিছু উপাদান ফিল্টার করতে চান তবে? ব্যক্তি.এজ> 3 এবং ব্যক্তি.ওয়েট> 50?
সেরিও

ধন্যবাদ। আমি ডায়নামিকএক্সপ্রেশনটি খুঁজে পাই না ars পার্সেলাম্বদা ()। এটি কোন নেমস্পেস এবং সমাবেশে রয়েছে?
ম্যাট ফিটজমুরিস

সব ভাল .. নেমস্পেসগুলির মধ্যে একটি অস্পষ্টতা ছিল। প্রয়োজন - E = System.Linq.Expressions ব্যবহার করে; System.Linq.Dynamic ব্যবহার করে;
ম্যাট ফিটজমৌরাইস

কেন এটি && এর পরিবর্তে 'এবং' ব্যবহার করে। এটি কি সি # কোড হওয়ার কথা নয়?
ট্রায়ঙ্কো

উত্তর:


65

Would গ্রন্থাগার linq গতিশীল এখানে সাহায্য করেছিল? বিশেষত, আমি একটি Whereধারা হিসাবে ভাবছি । যদি প্রয়োজন .Where(string)হয় তবে এটি কল করার জন্য এটি একটি তালিকা / অ্যারের ভিতরে রাখুন! অর্থাত

var people = new List<Person> { person };
int match = people.Where(filter).Any();

যদি তা না হয় তবে পার্সার লিখতে ( Expressionহুডের নীচে ব্যবহার করে ) প্রচুর পরিমাণে ট্যাক্স দেওয়া হয় না - আমি এক্স এর আগে আমার ট্রেনের যাতায়াতে অনুরূপ একটি লেখা (যদিও আমার কাছে উত্স নেই বলে মনে হয় না) ...


"পার্সার লেখার মাধ্যমে (হুডের নীচে এক্সপ্রেশন ব্যবহার করে)" পার্সিং এবং তারপরে একটি এক্সপ্রেশন ট্রি তৈরি করার অর্থ কী তা চিহ্নিত করুন বা সিস্টেম.লিনক.এক্সপ্রেসনের কিছু পার্সিং মেকানিজম রয়েছে?
একে_

আমি নিশ্চিত যে তিনি এমন একটি ফাংশনটি তৈরি করতে চেয়েছিলেন যা এইরকম গঠনের সাথে তৈরি হয় এবং তারপরে এটি একটি প্রাকটিক এবং সংকলিত হিসাবে অনুবাদ করা উচিত। প্রশ্নটি মনে হচ্ছে, আপনার ব্যাকরণটি 'স্ট্রিং' থেকে 'প্রিডিকেট' তে রূপান্তরিত করা। // Lambda expression as data in the form of an expression tree. System.Linq.Expressions.Expression<Func<int, bool>> expr = i => i < 5; // Compile the expression tree into executable code. Func<int, bool> deleg = expr.Compile(); // Invoke the method and print the output. Console.WriteLine("deleg(4) = {0}", deleg(4)); পার্সেলাম্বদা ভাল!
অদৃশ্যতা

31

এরকম আরও একটি গ্রন্থাগার ফ্লাই

আমি ডায়নামিক লিনক লাইব্রেরির একটি দ্রুত তুলনা করেছি এবং ফ্লি এবং ফ্লাই অভিব্যক্তির জন্য 10 গুণ বেশি দ্রুত ছিল"(Name == \"Johan\" AND Salary > 500) OR (Name != \"Johan\" AND Salary > 300)"

এইভাবে আপনি কীভাবে আপনার কোডটি লিখে ফেলতে পারেন।

static void Main(string[] args)
{
  var context = new ExpressionContext();
  const string exp = @"(Person.Age > 3 AND Person.Weight > 50) OR Person.Age < 3";
  context.Variables.DefineVariable("Person", typeof(Person));
  var e = context.CompileDynamic(exp);

  var bob = new Person
  {
    Name = "Bob",
    Age = 30,
    Weight = 213,
    FavouriteDay = new DateTime(2000, 1, 1)
  };

  context.Variables["Person"] = bob;
  var result = e.Evaluate();
  Console.WriteLine(result);
  Console.ReadKey();
}

সম্ভবত আমি কিছু মিস করছি, তবে কীভাবে 'পালানো' একটি লিনক এক্সপ্রেশন ট্রি তৈরি করতে সহায়তা করে?
মাইকেল বি হিলডেব্র্যান্ড

9
void Main()
{
    var testdata = new List<Ownr> {
        //new Ownr{Name = "abc", Qty = 20}, // uncomment this to see it getting filtered out
        new Ownr{Name = "abc", Qty = 2},
        new Ownr{Name = "abcd", Qty = 11},
        new Ownr{Name = "xyz", Qty = 40},
        new Ownr{Name = "ok", Qty = 5},
    };

    Expression<Func<Ownr, bool>> func = Extentions.strToFunc<Ownr>("Qty", "<=", "10");
    func = Extentions.strToFunc<Ownr>("Name", "==", "abc", func);

    var result = testdata.Where(func.ExpressionToFunc()).ToList();

    result.Dump();
}

public class Ownr
{
    public string Name { get; set; }
    public int Qty { get; set; }
}

public static class Extentions
{
    public static Expression<Func<T, bool>> strToFunc<T>(string propName, string opr, string value, Expression<Func<T, bool>> expr = null)
    {
        Expression<Func<T, bool>> func = null;
        try
        {
            var type = typeof(T);
            var prop = type.GetProperty(propName);
            ParameterExpression tpe = Expression.Parameter(typeof(T));
            Expression left = Expression.Property(tpe, prop);
            Expression right = Expression.Convert(ToExprConstant(prop, value), prop.PropertyType);
            Expression<Func<T, bool>> innerExpr = Expression.Lambda<Func<T, bool>>(ApplyFilter(opr, left, right), tpe);
            if (expr != null)
                innerExpr = innerExpr.And(expr);
            func = innerExpr;
        }
        catch (Exception ex)
        {
            ex.Dump();
        }

        return func;
    }
    private static Expression ToExprConstant(PropertyInfo prop, string value)
    {
        object val = null;

        try
        {
            switch (prop.Name)
            {
                case "System.Guid":
                    val = Guid.NewGuid();
                    break;
                default:
                    {
                        val = Convert.ChangeType(value, prop.PropertyType);
                        break;
                    }
            }
        }
        catch (Exception ex)
        {
            ex.Dump();
        }

        return Expression.Constant(val);
    }
    private static BinaryExpression ApplyFilter(string opr, Expression left, Expression right)
    {
        BinaryExpression InnerLambda = null;
        switch (opr)
        {
            case "==":
            case "=":
                InnerLambda = Expression.Equal(left, right);
                break;
            case "<":
                InnerLambda = Expression.LessThan(left, right);
                break;
            case ">":
                InnerLambda = Expression.GreaterThan(left, right);
                break;
            case ">=":
                InnerLambda = Expression.GreaterThanOrEqual(left, right);
                break;
            case "<=":
                InnerLambda = Expression.LessThanOrEqual(left, right);
                break;
            case "!=":
                InnerLambda = Expression.NotEqual(left, right);
                break;
            case "&&":
                InnerLambda = Expression.And(left, right);
                break;
            case "||":
                InnerLambda = Expression.Or(left, right);
                break;
        }
        return InnerLambda;
    }

    public static Expression<Func<T, TResult>> And<T, TResult>(this Expression<Func<T, TResult>> expr1, Expression<Func<T, TResult>> expr2)
    {
        var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
        return Expression.Lambda<Func<T, TResult>>(Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
    }

    public static Func<T, TResult> ExpressionToFunc<T, TResult>(this Expression<Func<T, TResult>> expr)
    {
        var res = expr.Compile();
        return res;
    }
}

LinqPad হয়েছে Dump()পদ্ধতি


GetProperty পদ্ধতি কোথায়?
অ্যালেন.টোমা

@ অ্যালেন.টোমা আমাকে সংকলনের জন্য কোডটি পরিবর্তন করতে var type = typeof(T); var prop = type.GetProperty(propName);হয়েছিল।
গাইলস রবার্টস

এটি তৈরি করে একটি আউটপুট সংকলন করে ফেলে দেয়
অমিত

5

আপনি ডিএলআর দেখে নিতে পারেন । এটি আপনাকে .NET 2.0 অ্যাপ্লিকেশনটির ভিতরে স্ক্রিপ্টগুলি মূল্যায়ণ এবং সম্পাদন করতে দেয়। আয়রণরবির সাথে এখানে একটি নমুনা রয়েছে :

using System;
using IronRuby;
using IronRuby.Runtime;
using Microsoft.Scripting.Hosting;

class App
{
    static void Main()
    {
        var setup = new ScriptRuntimeSetup();
        setup.LanguageSetups.Add(
            new LanguageSetup(
                typeof(RubyContext).AssemblyQualifiedName,
                "IronRuby",
                new[] { "IronRuby" },
                new[] { ".rb" }
            )
        );
        var runtime = new ScriptRuntime(setup);
        var engine = runtime.GetEngine("IronRuby");
        var ec = Ruby.GetExecutionContext(runtime);
        ec.DefineGlobalVariable("bob", new Person
        {
            Name = "Bob",
            Age = 30,
            Weight = 213,
            FavouriteDay = "1/1/2000"
        });
        var eval = engine.Execute<bool>(
            "return ($bob.Age > 3 && $bob.Weight > 50) || $bob.Age < 3"
        );
        Console.WriteLine(eval);

    }
}

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public int Weight { get; set; }
    public string FavouriteDay { get; set; }
}

অবশ্যই এই কৌশলটি রানটাইম মূল্যায়নের উপর ভিত্তি করে এবং সংকলনের সময় কোড যাচাই করা যায় না।


1
আমি 'খারাপ কোড' কার্যকর করার বিরুদ্ধে রক্ষা করতে সক্ষম হতে চাই ... এটি কি ভাল ফিট হবে?
কোডব্রায়েন

'খারাপ কোড' বলতে কী বোঝ? কেউ এমন একটি এক্সপ্রেশন টাইপ করছেন যা বৈধ নয়? এই ক্ষেত্রে স্ক্রিপ্টটি মূল্যায়নের চেষ্টা করার সময় আপনি একটি রানটাইম ব্যতিক্রম পাবেন।
ডারিন দিমিত্রভ

@ ডারিন, প্রক্রিয়া শুরু করা, ডেটা পরিবর্তন করা ইত্যাদির মতো জিনিসগুলি

2
'খারাপ কোড' = এমন কিছু যা ফানক <ব্যক্তি, বুল> টাইপের অভিব্যক্তি নয় (উদাহরণস্বরূপ ডিস্ক থেকে ফাইলগুলি মুছে ফেলা, কোনও প্রক্রিয়া কাটা ইত্যাদি ...)
কোডব্রেইন

1

পাটিগণিতের এক্সপ্রেশনগুলি বিশ্লেষণ এবং মূল্যায়নের জন্য এখানে একটি স্কালা ডিএসএল ভিত্তিক পার্সার সংযোজকের উদাহরণ।

import scala.util.parsing.combinator._
/** 
* @author Nicolae Caralicea
* @version 1.0, 04/01/2013
*/
class Arithm extends JavaTokenParsers {
  def expr: Parser[List[String]] = term ~ rep(addTerm | minusTerm) ^^
    { case termValue ~ repValue => termValue ::: repValue.flatten }

  def addTerm: Parser[List[String]] = "+" ~ term ^^
    { case "+" ~ termValue => termValue ::: List("+") }

  def minusTerm: Parser[List[String]] = "-" ~ term ^^
    { case "-" ~ termValue => termValue ::: List("-") }

  def term: Parser[List[String]] = factor ~ rep(multiplyFactor | divideFactor) ^^
    {
      case factorValue1 ~ repfactor => factorValue1 ::: repfactor.flatten
    }

  def multiplyFactor: Parser[List[String]] = "*" ~ factor ^^
    { case "*" ~ factorValue => factorValue ::: List("*") }

  def divideFactor: Parser[List[String]] = "/" ~ factor ^^
    { case "/" ~ factorValue => factorValue ::: List("/") }

  def factor: Parser[List[String]] = floatingPointConstant | parantExpr

  def floatingPointConstant: Parser[List[String]] = floatingPointNumber ^^
    {
      case value => List[String](value)
    }

  def parantExpr: Parser[List[String]] = "(" ~ expr ~ ")" ^^
    {
      case "(" ~ exprValue ~ ")" => exprValue
    }

  def evaluateExpr(expression: String): Double = {
    val parseRes = parseAll(expr, expression)
    if (parseRes.successful) evaluatePostfix(parseRes.get)
    else throw new RuntimeException(parseRes.toString())
  }
  private def evaluatePostfix(postfixExpressionList: List[String]): Double = {
    import scala.collection.immutable.Stack

    def multiply(a: Double, b: Double) = a * b
    def divide(a: Double, b: Double) = a / b
    def add(a: Double, b: Double) = a + b
    def subtract(a: Double, b: Double) = a - b

    def executeOpOnStack(stack: Stack[Any], operation: (Double, Double) => Double): (Stack[Any], Double) = {
      val el1 = stack.top
      val updatedStack1 = stack.pop
      val el2 = updatedStack1.top
      val updatedStack2 = updatedStack1.pop
      val value = operation(el2.toString.toDouble, el1.toString.toDouble)
      (updatedStack2.push(operation(el2.toString.toDouble, el1.toString.toDouble)), value)
    }
    val initial: (Stack[Any], Double) = (Stack(), null.asInstanceOf[Double])
    val res = postfixExpressionList.foldLeft(initial)((computed, item) =>
      item match {
        case "*" => executeOpOnStack(computed._1, multiply)
        case "/" => executeOpOnStack(computed._1, divide)
        case "+" => executeOpOnStack(computed._1, add)
        case "-" => executeOpOnStack(computed._1, subtract)
        case other => (computed._1.push(other), computed._2)
      })
    res._2
  }
}

object TestArithmDSL {
  def main(args: Array[String]): Unit = {
    val arithm = new Arithm
    val actual = arithm.evaluateExpr("(12 + 4 * 6) * ((2 + 3 * ( 4 + 2 ) ) * ( 5 + 12 ))")
    val expected: Double = (12 + 4 * 6) * ((2 + 3 * ( 4 + 2 ) ) * ( 5 + 12 ))
    assert(actual == expected)
  }
}

প্রদত্ত পাটিগণিতের প্রকাশের সমতুল্য অভিব্যক্তি গাছ বা পার্স গাছটি পার্সার [তালিকা [স্ট্রিং]] ধরণের হবে।

আরও বিশদ নীচের লিঙ্কে রয়েছে:

http://nicolaecaralicea.blogspot.ca/2013/04/scala-dsl-for-parsing-and-evaluating-of.html


0

ডায়নামিক লিনক লাইব্রেরি ছাড়াও (যা দৃ strongly়ভাবে টাইপড এক্সপ্রেশন তৈরি করে এবং দৃ strongly়ভাবে টাইপযুক্ত ভেরিয়েবলগুলির প্রয়োজন হয়) আমি আরও ভাল বিকল্পের পরামর্শ দিচ্ছি: লিনাক পার্সার যে এনআরেকো কমন্স লাইব্রেরির অংশ (মুক্ত উত্স) part এটি সমস্ত ধরণের সারিবদ্ধ করে এবং রানটাইমের সময় সমস্ত অনুরোধ সম্পাদন করে এবং গতিশীল ভাষার মতো আচরণ করে:

var lambdaParser = new NReco.LambdaParser();
var varContext = new Dictionary<string,object>();
varContext["one"] = 1M;
varContext["two"] = "2";

Console.WriteLine( lambdaParser.Eval("two>one && 0<one ? (1+8)/3+1*two : 0", varContext) ); // --> 5

0

যদিও এটি তুলনামূলকভাবে পুরানো পোস্ট - এটি এক্সপ্রেশন বিল্ডারের জন্য কোড: যেকোন পরিষেবা - এক্সপ্রেশনট্রিবিল্ডার এগুলি ইউনিট পরীক্ষা: অ্যানি সার্ভিস - এক্সপ্রেশনTreeBuilder ইউনিট টেস্ট

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.