Nice programing

.NET에 문자열 수학 평가 기가 있습니까?

nicepro 2020. 10. 6. 19:07
반응형

.NET에 문자열 수학 평가 기가 있습니까?


다음과 같은 유효한 수학 표현식이있는 문자열이있는 경우

String s = "1 + 2 * 7";

.NET에 해당 표현식을 구문 분석하고 평가하여 결과를 반환하는 내장 라이브러리 / 함수가 있습니까? 이 경우에 15.


Microsoft 스크립트 제어 라이브러리 (COM)에 대한 참조를 추가하고 이와 같은 코드를 사용하여 식을 평가할 수 있습니다. (JScript에서도 작동합니다.)

Dim sc As New MSScriptControl.ScriptControl()
sc.Language = "VBScript"
Dim expression As String = "1 + 2 * 7"
Dim result As Double = sc.Eval(expression)

편집 -C # 버전.

MSScriptControl.ScriptControl sc = new MSScriptControl.ScriptControl();
sc.Language = "VBScript";
string expression = "1 + 2 * 7";
object result = sc.Eval(expression);            
MessageBox.Show(result.ToString());

편집 -ScriptControl은 COM 개체입니다. 프로젝트의 "참조 추가"대화 상자에서 "COM"탭을 선택하고 "Microsoft Script Control 1.0"으로 스크롤 한 다음 확인을 선택합니다.


이 유명하고 오래된 질문에 내장 된 DataTable.Compute"트릭" 을 암시하는 답이 없다는 것이 이상합니다 . 여기있어.

double result = Convert.ToDouble(new DataTable().Compute("1 + 2 * 7", null));

다음 산술 연산자는 표현식에서 지원됩니다.

+ (addition)
- (subtraction)
* (multiplication)
/ (division)
% (modulus)

더 많은 정보 : DataColumn.Expression에서 표현 구문 .


Silverlight에서 C #으로 개발하는 모든 사용자를 위해 Javascript 엔진을 호출하여 표현식을 평가할 수있는 매우 깔끔한 트릭이 있습니다.

double result = (double) HtmlPage.Window.Eval("15 + 35");

당신은 본 적이 http://ncalc.codeplex.com를 ?

확장 가능하고 빠르므로 (예 : 자체 캐시가 있음) EvaluateFunction / EvaluateParameter 이벤트를 처리하여 런타임에 사용자 지정 함수와 변수를 제공 할 수 있습니다. 구문 분석 할 수있는 예제 표현식 :

Expression e = new Expression("Round(Pow(Pi, 2) + Pow([Pi2], 2) + X, 2)"); 

  e.Parameters["Pi2"] = new Expression("Pi * Pi"); 
  e.Parameters["X"] = 10; 

  e.EvaluateParameter += delegate(string name, ParameterArgs args) 
    { 
      if (name == "Pi") 
      args.Result = 3.14; 
    }; 

  Debug.Assert(117.07 == e.Evaluate()); 

또한 기본적으로 유니 코드 및 많은 데이터 유형을 처리합니다. 문법을 바꾸고 싶다면 녹용 파일과 함께 제공됩니다. 새로운 기능을로드하기 위해 MEF를 지원하는 포크도 있습니다.


실제로 일종의 내장형이 있습니다. XPath 네임 스페이스를 사용할 수 있습니다! XPath 표기법으로 확인하려면 문자열을 다시 형식화해야합니다. 간단한 표현식을 처리하기 위해 다음과 같은 방법을 사용했습니다.

    public static double Evaluate(string expression)
    {
        var xsltExpression = 
            string.Format("number({0})", 
                new Regex(@"([\+\-\*])").Replace(expression, " ${1} ")
                                        .Replace("/", " div ")
                                        .Replace("%", " mod "));

        return (double)new XPathDocument
            (new StringReader("<r/>"))
                .CreateNavigator()
                .Evaluate(xsltExpression);
    }

처음에는 muparser에 c # 래퍼를 사용 했습니다 . 이것은 매우 빠르다. 내가 아는 유일한 빠른 솔루션은 exprtk 입니다. 다른 솔루션을 찾고 있다면 벤치 마크를 확인할 수 있습니다 .

그러나 .Net의 경우 내장 지원을 사용하여 런타임에 코드를 컴파일 할 수 있습니다. 아이디어는 평가를위한 공식을 대체 할 수있는 임베디드 리소스와 같은 "템플릿"소스 파일을 갖는 것입니다. 그런 다음이 준비된 클래스 소스 코드를 컴파일러에 전달합니다.

기본 템플릿은 다음과 같습니다.

public class CSCodeEvaler
{
    public double EvalCode()
    {
        return last = Convert.ToDouble(%formula%);
    }

    public double last = 0;
    public const double pi = Math.PI;
    public const double e = Math.E;
    public double sin(double value) { return Math.Sin(value); }
    public double cos(double value) { return Math.Cos(value); }
    public double tan(double value) { return Math.Tan(value); }
    ...

식을 넣을 % formula %를 확인합니다.

컴파일하려면 CSharpCodeProvider 클래스를 사용하십시오. 여기에 완전한 소스를 넣고 싶지 않습니다. 그러나이 답변 이 도움 될 수 있습니다.

메모리 내 어셈블리를로드 한 후 클래스의 인스턴스를 만들고 EvalCode를 호출 할 수 있습니다.


최근에 저는 .NET과 JAVA를위한 수학 파서 라이브러리 인 mXparser를 사용하고있었습니다. mXparser는 기본 공식뿐만 아니라 매우 화려하고 복잡한 공식 (변수, 함수, 연산자, 반복 및 재귀 포함)을 지원합니다.

https://mxparser.codeplex.com/

http://mathparser.org/

몇 가지 사용 예 :

예 1 :

Expression e = new Expression("1+2*7 + (sin(10) - 2)/3");
double v = e.calculate();

예 2 :

Argument x = new Argument("x = 5");
Expression e = new Expression("2*x+3", x);
double v = e.calculate();

예 3 :

Function f = new Function("f(x,y) = sin(x) / cos(y)");
Expression e = new Expression("f(pi, 2*pi) - 2", f);
double v = e.calculate();

최근에 발견됨-구문을 시도하고 (고급 사용 사례를 확인하려는 경우) mXparser에서 제공하는 Scalar Calculator 다운로드 할 수 있습니다 .

친애하는


Roslyn을 사용할 수있는 또 다른 옵션 :

이를 위해 CodeAnalysis.CSharp.Scripting 라이브러리를 사용할 수 있습니다.

using Microsoft.CodeAnalysis.CSharp.Scripting;
using System;

namespace ExpressionParser
{
    class Program
    {
        static void Main(string[] args)
        {
            //Demonstrate evaluating C# code
            var result = CSharpScript.EvaluateAsync("System.DateTime.Now.AddDays(-1) > System.DateTime.Now").Result;
            Console.WriteLine(result.ToString());

            //Demonstrate evaluating simple expressions
            var result2 = CSharpScript.EvaluateAsync(" 5 * 7").Result;
            Console.WriteLine(result2);
            Console.ReadKey();
        }
    }
}

너겟 패키지 :

<package id="Microsoft.CodeAnalysis.Analyzers" version="1.1.0" targetFramework="net461" />
<package id="Microsoft.CodeAnalysis.Common" version="1.1.1" targetFramework="net461" />
<package id="Microsoft.CodeAnalysis.CSharp" version="1.1.1" targetFramework="net461" />
<package id="Microsoft.CodeAnalysis.CSharp.Scripting" version="1.1.1" targetFramework="net461" />
<package id="Microsoft.CodeAnalysis.Scripting" version="1.1.1" targetFramework="net461" />
<package id="Microsoft.CodeAnalysis.Scripting.Common" version="1.1.1" targetFramework="net461" />

아주 간단한 것이 필요하다면 DataTable:-)

Dim dt As New DataTable
dt.Columns.Add("A", GetType(Integer))
dt.Columns.Add("B", GetType(Integer))
dt.Columns.Add("C", GetType(Integer))
dt.Rows.Add(New Object() {12, 13, DBNull.Value})

Dim boolResult As Boolean = dt.Select("A>B-2").Length > 0

dt.Columns.Add("result", GetType(Integer), "A+B*2+ISNULL(C,0)")
Dim valResult As Object = dt.Rows(0)("result")

Jace ( https://github.com/pieterderycke/Jace )도 살펴 보겠습니다 . Jace는 모든 .NET 버전 (.NET 4.x, Windows Phone, Windows Store 등)을 지원하는 고성능 수학 파서 및 계산 엔진입니다. Jace는 NuGet을 통해서도 사용할 수 있습니다 : https://www.nuget.org/packages/Jace


간단한 수학 파서는 빌드하기가 매우 쉽고 몇 줄의 코드 만 필요합니다.

이 유연한 예를 들어 보겠습니다.

class RPN
{
    public static double Parse( Stack<string> strStk )
    {
        if (strStk == null || strStk.Count == 0 )
        {
            return 0;
        }
        Stack<double> numStk = new Stack<double>();
        double result = 0;

        Func<double, double> op = null;
        while (strStk.Count > 0)
        {
            var s = strStk.Pop();
            switch (s)
            {
                case "+":
                    op = ( b ) => { return numStk.Pop() + b; };
                    break;
                case "-":
                    op = ( b ) => { return numStk.Pop() - b; };
                    break;
                case "*":
                    op = ( b ) => { return numStk.Pop() * b; };
                    break;
                case "/":
                    op = ( b ) => { return numStk.Pop() / b; };
                    break;

                default:
                    double.TryParse(s, NumberStyles.Any, out result);
                    if (numStk.Count > 0)
                    {
                        result = op(result);
                    }
                    numStk.Push(result);
                    break;
            }
        }
        return result;
    }
}

....
var str = " 100.5 + 300.5 - 100 * 10 / 100";    
str = Regex.Replace(str, @"\s", "", RegexOptions.Multiline);
Stack<string> strStk = new Stack<string>(
     Regex.Split(str, @"([()*+\/-])", RegexOptions.Multiline).Reverse()
);
RPN.Parse(strStk);

스택 스택을 괄호로 묶어 우선 순위를 활성화하려면 재귀에 의해 아카이브되는 것과 같이 충분합니다. 괄호 사이의 모든 것은 새 스택에 배치됩니다. 마지막으로 람다가 깔끔하게 읽을 수있는 방식으로 수학 연산을 지원할 수 있습니다.


몇 년 전에 식 파서를 구현했고 최근 GitHubNuget : Albatross.Expression해당 버전을 게시했습니다 . 여기에는 다음과 같은 식 집합을 평가할 수있는 ExecutionContext 클래스가 포함되어 있습니다.

  • MV = 가격 * 수량;
  • 가격 = (매수 + 매도) / 2;
  • 입찰가 = .6;
  • 질문 = .8;

또한 스택 오버플로를 방지하는 데 유용한 순환 참조 검사가 내장되어 있습니다.


namespace CalcExp
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            double res = Evaluate("4+5/2-1");

            Console.WriteLine(res);

        }

        public static double Evaluate(string expression)
        {
            var xsltExpression =
                string.Format("number({0})",
                    new Regex(@"([\+\-\*])").Replace(expression, " ${1} ")
                                            .Replace("/", " div ")
                                            .Replace("%", " mod "));

// ReSharper disable PossibleNullReferenceException
            return (double)new XPathDocument
                (new StringReader("<r/>"))
                    .CreateNavigator()
                    .Evaluate(xsltExpression);
// ReSharper restore PossibleNullReferenceException
        }

    }
}

Flee Fast Lightweight Expression Evaluator

https://flee.codeplex.com

언어 참조

  • 산술 연산자 예 : a * 2 + b ^ 2-100 % 5
  • 비교 연산자 예 : a <> 100
  • AndOrXorNotOperators 예제 (논리적) : a> 100 And Not b = 100
  • ShiftOperators 예 : 100 >> 2
  • 연결 예 : "abc"+ "def"
  • 인덱싱 예 : arr [i + 1] + 100
  • 리터럴
  • 캐스팅 예 : 100 + cast (obj, int)
  • ConditionalOperator Example: If(a > 100 and b > 10, "both greater", "less")
  • InOperator Example (List): If(100 in (100, 200, 300, -1), "in", "not in")
  • Overloaded Operators On Types

Example :

Imports Ciloci.Flee
Imports Ciloci.Flee.CalcEngine
Imports System.Math

    Dim ec As New Ciloci.Flee.ExpressionContext
    Dim ex As IDynamicExpression
    ec.Imports.AddType(GetType(Math))

    ec.Variables("a") = 10            
    ec.Variables("b") = 40               
    ex = ec.CompileDynamic("a+b")

    Dim evalData    
    evalData = ex.Evaluate()
    Console.WriteLine(evalData)

The output : 50


MathNet.Symbolics

using System;
using static MathNet.Symbolics.SymbolicExpression;
using static System.Console;
using static System.Numerics.Complex;
using Complex = System.Numerics.Complex;

namespace MathEvaluator
{
    class Program
    {
        static readonly Complex i = ImaginaryOne;

        static void Main(string[] args)
        {
            var z = Variable("z");
            Func<Complex, Complex> f = Parse("z * z").CompileComplex(nameof(z));
            Complex c = 1 / 2 - i / 3;
            WriteLine(f(c));


            var x = Variable("x");
            Func<double, double> g = Parse("x * x + 5 * x + 6").Compile(nameof(x));
            double a = 1 / 3.0;
            WriteLine(g(a));
        }
    }
}

Don't forget to load

<PackageReference Include="MathNet.Symbolics" Version="0.20.0" />

참고URL : https://stackoverflow.com/questions/355062/is-there-a-string-math-evaluator-in-net

반응형