2009-09-17 12 views
17
を評価するための最短の道

式を評価するための多くのアルゴリズムは、例えば、があります。いずれかを評価する方法はベストと数式

  1. By Recursive Descent
  2. Shunting-yard algorithm
  3. Reverse Polish notation

ありますC#を使用して数学的表現。ネット反射や他の近代的なネット技術?

+0

私はしばらく前に同様の質問をしました。それらの答えのいくつかを見たいかもしれません:http://stackoverflow.com/questions/234217/is-it-possible-to-translate-a-user-entered-mathematical-equation-into-c-code-at – raven

+0

"static/pre-compiled"コードの残りの部分で使用されている変数にリンクする方法を見つけましたか? –

答えて

19

Thomasの回答に加えて、実際にはC#から(廃止予定の)JScriptライブラリに直接アクセスすることができます。つまり、JScriptのeval機能に相当するものを使用できます。

using Microsoft.JScript;  // needs a reference to Microsoft.JScript.dll 
using Microsoft.JScript.Vsa; // needs a reference to Microsoft.Vsa.dll 

// ... 

string expr = "7 + (5 * 4)"; 
Console.WriteLine(JScriptEval(expr)); // displays 27 

// ... 

public static double JScriptEval(string expr) 
{ 
    // error checking etc removed for brevity 
    return double.Parse(Eval.JScriptEvaluate(expr, _engine).ToString()); 
} 

private static readonly VsaEngine _engine = VsaEngine.CreateEngine(); 
+0

恥ずかしがり屋のためのキャレット^をサポートしていません。 –

13

確かに可能です。基本的にはCodeSnippetCompileUnitクラスです。 私はいくつかの使用コード例を書いています。これらの名前空間を含める必要があります:

  • System.CodeDom.Compiler;
  • System.CodeDom;
  • Microsoft.CSharp;
  • System.Reflection;

は、ここでは、コードです:

string source = @" 
class MyType 
{ 
    public static int Evaluate(<!parameters!>) 
    { 
     return <!expression!>; 
    } 
} 
"; 

string parameters = "int a, int b, int c"; 
string expression = "a + b * c"; 

string finalSource = source.Replace("<!parameters!>", parameters).Replace("<!expression!>", expression); 

CodeSnippetCompileUnit compileUnit = new CodeSnippetCompileUnit(finalSource); 
CodeDomProvider provider = new CSharpCodeProvider(); 

CompilerParameters parameters = new CompilerParameters(); 

CompilerResults results = provider.CompileAssemblyFromDom(parameters, compileUnit); 

Type type = results.CompiledAssembly.GetType("MyType"); 
MethodInfo method = type.GetMethod("Evaluate"); 

// The first parameter is the instance to invoke the method on. Because our Evaluate method is static, we pass null. 
int result = (int)method.Invoke(null, new object[] { 4, -3, 2 }); 

は、「パラメータ」と何によって「表現」を置き換え、そしてあなた自身に、一般的な式評価を持っています。

results.CompiledAssemblyでFileNotFoundExceptionが発生した場合、スニペットのコンパイルに失敗しました。

また、System.CodeDom.CodeSnippetExpressionクラスも参照してください。式をより具体的に読むために使用されますが、式自体はコンパイルできません。そのため、より多くのCodeDomを使用して、その周囲の作業クラスおよびメソッドを構築する必要があります。これは、生成しているクラスの種類をプログラムで操作できるようにする場合に便利です。 CodeSnippetCompileUnitは、ワーキングクラス全体を一度に生成するのはいいですが(例の方が簡単ですが)、不便な文字列操作をしなければならない場合は、それを操作してください。

+0

が最適です。 –

+0

ncalcを使ったこのソリューションのパフォーマンスは非常に高く、グラファとしてテストしました。多変数関数の中には500sを超えるものがありました。これにより、400,000ポイントを超える5s以下の描画ができました。素晴らしい解決策! –

3

コンパイラサービスを使用するのはシンプルで効率的な解決方法ですが、実際には何かを実行する可能性があるため、ユーザーが式を入力すると深刻なセキュリティ問題が発生します。

さらに安全性の高い別の非常に簡単なソリューションがあります.JScript Evalの機能を活用してください。あなただけのこれらの手順を実行する必要があります。

がJsMath.jsという名前のjsファイルを作成します。

class JsMath 
{ 
    static function Eval(expression : String) : double 
    { 
     return eval(expression); 
    }; 
} 

クラスライブラリにそれをコンパイルします。

jsc /t:library JsMath.js 

リファレンスあなたのC#プロジェクトでJsMathライブラリをそれを次のように使用してください:

double result = JsMath.Eval(expression); 
+0

私はセキュリティを考慮したこともなく、JScriptのeval関数についても知りませんでした。これは私の解決策よりも簡潔です。いい答えだ! – Joren

+0

実際には、中間のJScriptコンパイルステップを使わずに、C#から直接 'eval'関数にアクセスすることができます。詳細は私の答えを見てください。 – LukeH

+0

コンパイラサービスを使用するセキュリティの問題を避けるために、ANTLを使用してユーザーの式を事前に解析し、奇妙な入力を回避します。パフォーマンスを探しているなら、 'eval()'関数がうまくいかないかもしれません。 –

3

私にとってVici.Parserは非常にうまく動作します:check it out here、それは私が今までに見つけた最も柔軟な表現パーサーです。

例が利用可能であり、非常に良いサポートは開発者によってあります(私たちは、SQL Serverデータベースが提供するデータを、「人間が読めるのビジネスルールを設定するためにそれを使用しました)(ウェブサイトのを確認してくださいフォーラム)。

+0

非常に興味深いです。 – NotMe

+1

@Roel - リンクが死んでいます。 –

3

ncalcが最適です。 codeplexでもナゲットで見つけることができます。
NCalcは、.NETの数式の評価者です。 NCalcは、任意の式を解析し、静的または動的パラメータおよびカスタム関数を含む結果を評価することができます。

1

私はこれがすべての最良の方法だと思います。 Petar Repac's answerは素晴らしいです。 のDataColumnオブジェクトの「式」引数を使用すると、信じられないほど簡単に話題を解決します

static double Evaluate(string expression) 
{ 
    var loDataTable = new DataTable(); 
    var loDataColumn = new DataColumn("Eval", typeof(double), expression); 
    loDataTable.Columns.Add(loDataColumn); 
    loDataTable.Rows.Add(0); 
    return (double)(loDataTable.Rows[0]["Eval"]); 
} 
関連する問題