.NETに文字列数学エバリュエーターはありますか?


93

次のような有効な数式を含む文字列がある場合:

String s = "1 + 2 * 7";

その式を解析して評価して結果を返す.NETの組み込みライブラリ/関数はありますか?この場合、15。


2
組み込みではありません。しかし、ここにはかなり包括的なものがあります
Strelok


1
式エバリュエーター(100%マネージド.NETのEval関数)を使用できます
jadsc

C#で数式を評価するためのコードのみのソリューションを作成しました。コードはblackbeltcoder.com/Articles/algorithms/ac-expression-evaluatorで確認できます。
ジョナサンウッド

このライブラリにはいくつかのバグがあるようです。
Philippe Lavoie、2011年

回答:


53

Microsoft Script Control Library(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]までスクロールして[OK]を選択します。


2
これは答えとしてマークされていますが、10年前のことであり、COMは今ややや死んでいます。以下のDataTable.Computeの回答をお勧めします。
ドウィリス

62

この有名で古い質問には、組み込みのDataTable.Compute「トリック」を示唆する答えがありません。ここにあります。

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

次の算術演算子が式でサポートされています。

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

その他の情報:DataColumn.Expression表現の構文


11月15日、11月15日にma81xxから回答がありました
tatigo、

1
その通りですが、それはComputeメソッドを使用していませんでした。
Tim Schmelter

あなたの例は私にSystem.InvalidCastExceptionがユーザーコードによって処理されなかったことを示しますHResult = -2147467262どうすれば修正できますか?
Yuliia Ashomok 2015年

それは私のために働きます、あなたはこのサンプルコードを使いましたか?デバッガーを使用して結果の値を検査します。タイプが示されています。
Tim Schmelter、2015年

28

SilverlightのC#で開発している人のために、JavaScriptエンジンを呼び出すことで式の評価を可能にする、私が発見したかなり巧妙なトリックを以下に示します。

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

これを他の場所で参照できますか。おそらくそうではありませんが、それはクールです。
Joel Coehoorn、2009年

4
これは任意のJavascriptコードを評価するので、入力を無害化し、結果を直接表示しないようにする必要があります。(これは、XSSを実現せずに導入する良い方法だと思います)
Dan Esparza

先頭にゼロを付けて数値を入力してください。結果は信頼できません。「054 + 6」は、たとえば50を与えます。
テリー

9
@djerry、これは、先行ゼロ付きの数値がJSのエバリュエーターによって8進数と見なされ、8進数の054が10進数の44に等しいためです。
AndréLeria

24

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

また、Unicodeや多くのデータ型をネイティブで処理します。文法を変更したい場合は、アントラーファイルが付属しています。新しい関数をロードするためにMEFをサポートするフォークもあります。


1
素晴らしい図書館。NUGETでも利用可能
Paul Grimshaw

これは、ユーザーの入力を受け取る微分方程式ソルバーに使用したものです。質問はこちら
kleineg

15

実際には、組み込みのようなものがあります-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);
    }

12

最初はmuparserの c#ラッパーを使用しました。これは非常に高速でした。私が知っている唯一のより速い解決策はexprtkです。他のソリューションを探している場合は、ベンチマークをチェックアウトできます

ただし、.Netの場合、組み込みサポートを使用して実行時にコードをコンパイルできます。たとえば、評価用の式を置き換えることができる埋め込みリソースとして「テンプレート」ソースファイルを用意することです。次に、この準備されたclass-source-codeをコンパイラに渡します。

基本的なテンプレートは次のようになります。

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を呼び出すことができます。


9

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

nugetパッケージ:

<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" />

2
これが今の答えになるはずです
sonofaforester

8

最近、私は.NETとJAVAの数学パーサーライブラリであるmXparserを使用していました。mXparserは、基本的な式だけでなく、非常に凝った/複雑な式(変数、関数、演算子、反復、再帰を含む)もサポートしています。

https://mxparser.codeplex.com/

https://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を搭載したスカラー 計算 アプリをダウンロードできます。

宜しくお願いします


これは私が見つけた最高のライブラリです。ただし、数値以外のデータ型はサポートしていません。DateTimeとStringが必要です。良い代替手段がありますか。
Homam 2018

5

非常にシンプルなものが必要な場合は、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")


3

単純な数学パーサーは非常に簡単に構築でき、数行のコードしか必要としません。

この柔軟な例を見てみましょう:

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

再帰によってアーカイブするなど、スタックのスタックをブラケットで囲んで優先順位を有効にするには十分です。大括弧で囲まれたものはすべて新しいスタックに置かれます。最後に、ラムダを使用して、数学の演算を読みやすい方法でサポートできます。


回答を確認することをお勧めします。 100.5 + 300.5 - 100 * 10 / 100 = 30.1vs391
タワニ2017

1
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
        }

    }
}

3
-1:これを@cbp回答にマージします。私たちが1つの素晴らしい答えを持つことができるとき、基本的に同一である2つの答えを持つ必要はゼロです。
Robert MacLean 2014年

1

数年前に式パーサーを実装し、そのバージョンをGitHubNuget:Albatross.Expressionで最近公開しました。次のような式のセットを評価できるExecutionContextクラスが含まれています。

  • MV =価格*数量;
  • 価格=(入札+質問)/ 2;
  • 入札= 0.6;
  • 尋ねる= 0.8;

また、スタックオーバーフローを回避するのに役立つ循環参照チェックも組み込まれています。


1

私が作成しているMath-Expression-Evaluatorライブラリを使用できます。それは、次のような単純な式をサポートし2.5+5.917.89-2.47+7.165/2/2+1.5*3+4.58、括弧付きの式(((9-6/2)*2-4)/2-6-1)/(2+24/(2+4))の変数を持つと式:

var a = 6;
var b = 4.32m;
var c = 24.15m;
var engine = new ExpressionEvaluator();
engine.Evaluate("(((9-a/2)*2-b)/2-a-1)/(2+c/(2+4))", new { a, b, c});

名前付き変数としてパラメーターを渡すこともできます。

dynamic dynamicEngine = new ExpressionEvaluator();

var a = 6;
var b = 4.5m;
var c = 2.6m;

dynamicEngine.Evaluate("(c+b)*a", a: 6, b: 4.5, c: 2.6);

.Net Standard 2.0をサポートしているため、.Net Coreおよび.Net Full Frameworkプロジェクトから使用でき、外部依存関係はありません。


0

Flee Fast Lightweight Expression Evaluator

https://flee.codeplex.com

言語リファレンス

  • ArithmeticOperatorsの例:a * 2 + b ^ 2-100%5
  • ComparisonOperatorsの例:a <> 100
  • AndOrXorNotOperatorsの例(論理):a> 100およびNot b = 100
  • ShiftOperatorsの例:100 >> 2
  • 連結の例: "abc" + "def"
  • インデックスの例:arr [i + 1] + 100
  • リテラル
  • キャストの例:100 + cast(obj、int)
  • ConditionalOperatorの例:If(a> 100およびb> 10、「両方大きい」、「小さい」)
  • InOperatorの例(リスト):If(100 in(100、200、300、-1)、 "in"、 "not in")
  • 型のオーバーロードされた演算子

例:

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)

出力:50


0

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

ロードすることを忘れないでください

<PackageReference Include="MathNet.Symbolics" Version="0.20.0" />
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.