2009-09-17 23 views
17
मूल्यांकन करने के लिए

भाव का मूल्यांकन करने के लिए कई एल्गोरिदम उदाहरण के लिए, कर रहे हैं:बेस्ट और सबसे छोटा रास्ता गणितीय अभिव्यक्ति

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

वहाँ किसी भी मूल्यांकन करने के लिए कोई तरीका है सी # .नेट प्रतिबिंब या अन्य आधुनिक .NET प्रौद्योगिकी का उपयोग कर गणितीय अभिव्यक्ति?

+0

मैं एक ऐसी ही सवाल एक समय पहले पूछा। आप उन उत्तरों में से कुछ को देखना चाह सकते हैं: http://stackoverflow.com/questions/234217/is-it-possible-to-translate-a-user-entered-mathematical-equation-into-c-code-at – raven

+0

क्या आपको शेष "स्थिर/पूर्व-संकलित" कोड में उपयोग किए गए चर से लिंक करने का कोई तरीका मिला है? –

उत्तर

19

थॉमस के उत्तर के आगे, वास्तव में सी # से सीधे (बहिष्कृत) जेस्क्रिप्ट पुस्तकालयों तक पहुंचना संभव है, जिसका अर्थ है कि आप जेस्क्रिप्ट के 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;
  • सिस्टम। कोडडॉम;
  • माइक्रोसॉफ्ट .CSharp;
  • सिस्टम। प्रतिबिंब;

कोड यह रहा:

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

बदलें 'पैरामीटर' और जो कुछ भी द्वारा 'अभिव्यक्ति', और तुम अपने आप को एक सामान्य अभिव्यक्ति मूल्यांकनकर्ता मिल गया है।

यदि आपको परिणामों में FileNotFoundException मिलता है। कॉम्प्लेटेडएस्क्रिप्ट, तो स्निपेट संकलित करने में विफल रहा।

आप सिस्टम.कोडडॉम.कोड स्निपेट एक्स्पेरियन क्लास को भी देखना चाहते हैं। इसका उपयोग अधिक विशेष रूप से अभिव्यक्तियों को पढ़ने के लिए किया जाता है, लेकिन स्वयं द्वारा एक अभिव्यक्ति संकलित नहीं की जा सकती है, इसलिए आपको एक वर्किंग क्लास और इसके आसपास की विधि बनाने के लिए अधिक कोडडॉम का उपयोग करना होगा। यह उपयोगी है यदि आप प्रोग्रामेटिक रूप से हेरफेर करने में सक्षम होना चाहते हैं कि आप किस प्रकार की कक्षा बना रहे हैं। CodeSnippetCompileUnit एक बार में एक संपूर्ण मजदूर वर्ग उत्पन्न करने के लिए अच्छा है (और उदाहरण के लिए सरल) लेकिन इसे कुशल बनाने के लिए आपको असुविधाजनक स्ट्रिंग मैनिप्लेशंस करना होगा।

+0

सबसे अच्छा समाधान। –

+0

रिकॉर्ड के लिए, एनकेसीसी का उपयोग करने पर इस समाधान का प्रदर्शन बहुत बड़ा है, मैंने इसे एक गैपर के लिए परीक्षण किया और कुछ बहु परिवर्तनीय कार्यों को प्लॉट करने के लिए 500 से अधिक समय लगे, इसने मुझे 400,000 से अधिक अंक प्लॉट करने में 5 से कम समय लगाया। महान समाधान! –

3

हालांकि कंपाइलर सेवाओं का उपयोग करना एक सरल और कुशल समाधान है, यदि उपयोगकर्ता द्वारा अभिव्यक्ति दर्ज की जाती है तो यह गंभीर सुरक्षा समस्याएं उठाती है, क्योंकि यह लगभग कुछ भी निष्पादित कर सकती है।

एक और बहुत आसान समाधान है जो अधिक सुरक्षित है: जेस्क्रिप्ट Eval फ़ंक्शन का लाभ उठाएं।

एक js फ़ाइल बनाएँ नामित JsMath.js:

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

एक वर्ग पुस्तकालय में संकलित करें: आप बस इन चरणों का पालन करने की आवश्यकता

jsc /t:library JsMath.js 

संदर्भ अपने सी # परियोजना में JsMath पुस्तकालय , और इस तरह इसका इस्तेमाल:

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

मैंने सुरक्षा को कभी भी नहीं माना, न ही मुझे जेस्क्रिप्ट eval फ़ंक्शन के बारे में पता था। यह मेरे समाधान से भी अधिक संक्षिप्त है। अच्छा उत्तर! – Joren

+0

इंटरमीडिएट जेस्क्रिप्ट संकलन चरण के बिना सीधे सी # से 'eval' फ़ंक्शन तक पहुंचना संभव है। विवरण के लिए मेरा जवाब देखें। – LukeH

+0

कंपाइलर सेवाओं का उपयोग करके सुरक्षा समस्याओं से बचने के लिए मैं एंटएल का उपयोग पूर्व अभिव्यक्ति उपयोगकर्ता अभिव्यक्ति के लिए करता हूं और किसी भी अजीब इनपुट से बचता हूं। यदि आप प्रदर्शन की तलाश में हैं तो 'eval()' फ़ंक्शन काम नहीं कर सकता है। –

3

मेरे लिए Vici.Parser बहुत अच्छी तरह से काम करता है: check it out here, यह अब तक का सबसे लचीला अभिव्यक्ति पार्सर है।

(हम इसे का उपयोग किया है अप 'मानव पठनीय' व्यावसायिक नियम निर्धारित करने के लिए, एक SQL सर्वर डेटाबेस से उपलब्ध कराए गए आंकड़ों के साथ)

उदाहरण उपलब्ध हैं और डेवलपर द्वारा एक बहुत अच्छा समर्थन है (वेबसाइट की जाँच मंच)।

+0

बहुत दिलचस्प लग रहा है। – NotMe

+1

@ रोएल - लिंक मर चुका है। –

3

ncalc सबसे अच्छा है। आप इसे codeplex में भी गले में पा सकते हैं।
एनसीएएलसी एनईटी में गणितीय अभिव्यक्ति मूल्यांकनकर्ता है। एनसीएएलसी किसी भी अभिव्यक्ति को पार्स कर सकता है और परिणाम का मूल्यांकन कर सकता है, जिसमें स्थिर या गतिशील पैरामीटर और कस्टम फ़ंक्शंस शामिल हैं।

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"]); 
} 
संबंधित मुद्दे