2008-10-06 32 views
19

के रूप में मुझे एक गणितीय अभिव्यक्ति का मूल्यांकन करने की आवश्यकता है जो मुझे सी # में एक स्ट्रिंग के रूप में प्रस्तुत किया गया है। उदाहरण noddy लेकिन अभिव्यक्ति के रूप में स्ट्रिंग भर में बिंदु मिलता है।ऑपरेटर स्ट्रिंग्स

मुझे एक int को पॉप्युलेट करने के लिए मूल्यांकन की आवश्यकता है।

वहाँ ... दूसरों langugaes में की तरह कोई eval() सी # में है

String myString = "3*4"; 

संपादित करें:

मैं VS2008

Microsoft.JScript की कोशिश की पर कर रहा हूँ। = इसकी पदावनत विधि (लेकिन अभी भी अनुरूप है - चेतावनी)

हालांकि Microsoft.JScript dll कि मैं doens

सार्वजनिक वस्तु InvokeMember काम करा सकते हैं (स्ट्रिंग नाम, BindingFlags invokeAttr, बाइंडर बांधने की मशीन, वस्तु लक्ष्य , वस्तु [] तर्क);

शिकायत करता है कि एक गायब है ";" आंकड़ा जाना ...

संपादित 2

समाधान - codeDom एक था - यह के रूप में वहाँ कोई सुरक्षा समस्या हैं के लिए काम किया - केवल मुझे कभी कोड चल रहा हो जा रहा है। उत्तर के लिए बहुत धन्यवाद ...

और करने के लिए नए ड्रैगन बुक भयानक लिंक

संपादित 3

मैट dataTable.Compute() भी काम करता है - यहां तक ​​कि सुरक्षा के प्रति जागरूक करने के लिए बेहतर है। (पैरामीटर जांच नोट किया गया)

+0

यह – rshimoda

+0

पूछने के लिए धन्यवाद, आप http://Ncalc.codeplex.com पर भी देख सकते हैं जैसा कि मैंने अपने उत्तर में सुझाव दिया है, जो मुझे समझ में नहीं आ रहा है। – GreyCloud

उत्तर

13

जिस तरह से मैं इसे देखता हूं, आपके पास दो विकल्प हैं - एक अभिव्यक्ति मूल्यांकनकर्ता का निर्माण करें या निर्माण करें, संकलित करें और फ्लाई पर सी # कोड चलाएं।

मैं एक अभिव्यक्ति मूल्यांकनकर्ता पुस्तकालय के साथ जाऊंगा, क्योंकि आपको किसी भी सुरक्षा समस्या के बारे में चिंता करने की आवश्यकता नहीं है। यही है, हो सकता है कि आप माध्यमिक ट्रस्ट वातावरण में कोड जनरेशन का उपयोग करने में सक्षम न हों, जैसे कि अधिकांश साझा होस्टिंग सर्वर। http://www.vbforums.com/showthread.php?t=397264

+0

vbfourms ने नौकरी धन्यवाद –

+0

हाय - डॉटमैथ लाइब्रेरी वर्कस्पेस.गोडॉटॉट.नेट से माइग्रेट नहीं हुई है - जब उनके पास msdn में संक्रमण होता है ... –

+0

हाँ :(लगता है कोडप्लेक्स पर उपलब्ध हालांकि: http://www.codeplex.com/dotMath/Release/ProjectReleases.aspx?ReleaseId=875 –

1

जब आप कहते हैं, "अन्य भाषाओं की तरह" आपको "गतिशील भाषाओं की तरह" कहना चाहिए।

पाइथन, रूबी, और कई की गतिशील भाषाओं के लिए भाषाओं का अर्थ है, एक Eval() फ़ंक्शन एक प्राकृतिक तत्व है। वास्तव में, यह संभवतः अपने आप को लागू करने के लिए भी बहुत छोटा है। यह कोर एक स्थिर, दृढ़ता से टाइप, संकलित मंच (कम से कम जब तक गतिशील भाषा क्रम और अधिक समर्थन हो जाता है) है पर

Howver, नेट है। इसमें कोड-इंजेक्शन सुरक्षा और संकलन-समय प्रकार की जांच जैसे प्राकृतिक फायदे हैं जिन्हें अनदेखा करना कठिन होता है। लेकिन इसका मतलब है कि एक Eval() फ़ंक्शन इतना अच्छा फिट नहीं है- यह समय से पहले अभिव्यक्ति को संकलित करने में सक्षम होना चाहता है। इस तरह के मंच में, आम तौर पर अन्य, सुरक्षित, एक ही कार्य को पूरा करने के तरीके होते हैं।

+0

मान लीजिए कि आपने JScript.Net को याद किया .. – NotMe

+0

गैंबिट स्कीम एक गतिशील, दृढ़ता से टाइप किया गया, (वैकल्पिक रूप से) संकलित प्लेटफ़ॉर्म है, और यह eval है। –

+0

लॉल: अपवाद जो नियम साबित करते हैं। –

0

एक व्याख्या की गई भाषा में आपको दुभाषिया का उपयोग करके स्ट्रिंग का मूल्यांकन करने का मौका मिल सकता है। सी # में आपको स्ट्रिंग लिखी गई भाषा के लिए एक पार्सर चाहिए (गणितीय अभिव्यक्ति की भाषा)। यह एक गैर-तुच्छ अभ्यास है। यदि आप इसे करना चाहते हैं, तो एक पुनरावर्ती-मूल पार्सर का उपयोग करें। अहो, सेठी और उलमैन द्वारा पहली बार "ड्रैगन बुक" (कंपाइलर्स: डिज़ाइन इत्यादि) के प्रारंभिक अध्याय - 1 एड 1 9 77 या द्वितीय संस्करण 2007) में आपको क्या करना है, इसकी एक अच्छी व्याख्या है।

आपके प्रोजेक्ट में एक विकल्प हो सकता है जो कि पर्ल में लिखा गया एक घटक है, जो अब .NET के लिए उपलब्ध होना चाहिए, और मूल्यांकन करने के लिए पर्ल का उपयोग करें।

0

jscript interpreter कर सकता है, या अभिव्यक्ति सरल है, तो आप अपना खुद का पार्सर लिख सकते हैं (सावधान रहें, यह वास्तव में जटिल हो जाता है)।

मुझे पूरा यकीन है कि सी # में कोई प्रत्यक्ष "Eval (string)" विधि नहीं है क्योंकि इसका अर्थ नहीं है।

ध्यान रखें कि हालांकि कोड व्याख्या कोड इंजेक्शन के अधीन है, अतिरिक्त सावधान :)

0

आप जब एक अभिव्यक्ति की गणना अन्य चरों के मान का उपयोग करने की आवश्यकता होगी हो सकता है?

+0

कोई न सिर्फ परिणाम = धन्यवाद deestan –

0

कुछ Googling के बाद, मैं देख रहा हूँ वहाँ बना सकते हैं और मक्खी CodeDom के प्रयोग पर कोड को संकलित करने के संभावना है:

यहाँ भाव का मूल्यांकन करने के कोड पैदा करने के लिए एक उदाहरण है। (tutorial देखें)।

मैं व्यक्तिगत रूप से नहीं सोचता कि दृष्टिकोण एक बहुत अच्छा विचार है, क्योंकि उपयोगकर्ता जो भी कोड चाहता है उसे दर्ज कर सकता है, लेकिन यह एक क्षेत्र हो सकता है (उदाहरण के लिए केवल इनपुट को सत्यापित करके, और केवल संख्याओं को अनुमति देकर और सरल गणित संचालन)।

21

सभी अन्य उत्तर संभव overkill है।

यदि आपको केवल सरल अंकगणित की आवश्यकता है, तो ऐसा करें।

 DataTable dummy = new DataTable(); 
     Console.WriteLine(dummy.Compute("15/3",string.Empty)); 

संपादित करें: थोड़ी अधिक जानकारी। System.Data.DataColumn कक्षा की Expression संपत्ति के लिए एमएसडीएन दस्तावेज़ देखें। "अभिव्यक्ति सिंटेक्स" पर सामान अंकगणितीय ऑपरेटरों के अतिरिक्त उपयोग किए जा सकने वाले आदेशों की एक सूची को रेखांकित करता है। (उदा। आईआईएफ, एलईएन, आदि)। मेरे पहले पोस्ट किए गए उत्तर को वोट देने के लिए सभी को धन्यवाद!

+0

अच्छा छोटा हैक। बस जिज्ञासा: यह खराब इनपुट के लिए कैसे व्यवहार करेगा? –

+0

अच्छा यह भी काम करता है => बहुत धन्यवाद मैट –

+0

यह एक सिस्टम फेंकता है। डेटा। मूल्यांकन मूल्यांकन करें या सिस्टम। डेटा। सिंटेक्सएररएक्सप्शन आपको बता रहा है क्या गलत है। –

0

कुछ अन्य सुझाव:

  • मोनो 2.0 (आज बाहर आया था) एक eval विधि है।
  • आप आसानी से बू में एक छोटा डोमेन लिख सकते हैं।
  • आप एक पुराने स्कूल रिकर्सिव-वंश ईबीएनएफ पार्सर बना सकते हैं।
11

मैंने इसे कुछ सप्ताह पहले सी # में व्यक्तिगत व्यायाम के रूप में किया था।

यह काफी कोड है और स्थानों पर खराब टिप्पणी की गई है। लेकिन यह कई परीक्षण मामलों के साथ काम किया।

का आनंद लें!

using System; 
using System.Collections.Generic; 
using System.Text.RegularExpressions; 

namespace StackOverflow 
{ 
    class Start 
    { 
     public static void Main(string[] args) 
     { 
      Evaluator ev; 
      string variableValue, eq; 
     Console.Write("Enter equation: "); 
     eq = Console.ReadLine(); 

     while (eq != "quit") 
     { 
      ev = new Evaluator(eq); 
      foreach (Variable v in ev.Variables) 
      { 
       Console.Write(v.Name + " = "); 
       variableValue = Console.ReadLine(); 
       ev.SetVariable(v.Name, Convert.ToDecimal(variableValue)); 
      } 

      Console.WriteLine(ev.Evaluate()); 

      Console.Write("Enter equation: "); 
      eq = Console.ReadLine(); 
     } 
    } 
} 

class EvalNode 
{ 
    public virtual decimal Evaluate() 
    { 
     return decimal.Zero; 
    } 
} 

class ValueNode : EvalNode 
{ 
    decimal value; 

    public ValueNode(decimal v) 
    { 
     value = v; 
    } 

    public override decimal Evaluate() 
    { 
     return value; 
    } 

    public override string ToString() 
    { 
     return value.ToString(); 
    } 
} 

class FunctionNode : EvalNode 
{ 
    EvalNode lhs = new ValueNode(decimal.Zero); 
    EvalNode rhs = new ValueNode(decimal.Zero); 
    string op = "+"; 

    public string Op 
    { 
     get { return op; } 
     set 
     { 
      op = value; 
     } 
    } 

    internal EvalNode Rhs 
    { 
     get { return rhs; } 
     set 
     { 
      rhs = value; 
     } 
    } 

    internal EvalNode Lhs 
    { 
     get { return lhs; } 
     set 
     { 
      lhs = value; 
     } 
    } 

    public override decimal Evaluate() 
    { 
     decimal result = decimal.Zero; 

     switch (op) 
     { 
      case "+": 
       result = lhs.Evaluate() + rhs.Evaluate(); 
       break; 

      case "-": 
       result = lhs.Evaluate() - rhs.Evaluate(); 
       break; 

      case "*": 
       result = lhs.Evaluate() * rhs.Evaluate(); 
       break; 

      case "/": 
       result = lhs.Evaluate()/rhs.Evaluate(); 
       break; 

      case "%": 
       result = lhs.Evaluate() % rhs.Evaluate(); 
       break; 

      case "^": 
       double x = Convert.ToDouble(lhs.Evaluate()); 
       double y = Convert.ToDouble(rhs.Evaluate()); 

       result = Convert.ToDecimal(Math.Pow(x, y)); 
       break; 

      case "!": 
       result = Factorial(lhs.Evaluate()); 
       break; 
     } 

     return result; 
    } 

    private decimal Factorial(decimal factor) 
    { 
     if (factor < 1) 
      return 1; 

     return factor * Factorial(factor - 1); 
    } 

    public override string ToString() 
    { 
     return "(" + lhs.ToString() + " " + op + " " + rhs.ToString() + ")"; 
    } 
} 

public class Evaluator 
{ 
    string equation = ""; 
    Dictionary<string, Variable> variables = new Dictionary<string, Variable>(); 

    public string Equation 
    { 
     get { return equation; } 
     set { equation = value; } 
    } 

    public Variable[] Variables 
    { 
     get { return new List<Variable>(variables.Values).ToArray(); } 
    } 

    public void SetVariable(string name, decimal value) 
    { 
     if (variables.ContainsKey(name)) 
     { 
      Variable x = variables[name]; 
      x.Value = value; 
      variables[name] = x; 
     } 
    } 

    public Evaluator(string equation) 
    { 
     this.equation = equation; 
     SetVariables(); 
    } 

    public decimal Evaluate() 
    { 
     return Evaluate(equation, new List<Variable>(variables.Values)); 
    } 

    public decimal Evaluate(string text) 
    { 
     decimal result = decimal.Zero; 
     equation = text; 
     EvalNode parsed; 

     equation = equation.Replace(" ", ""); 

     parsed = Parse(equation, "qx"); 

     if (parsed != null) 
      result = parsed.Evaluate(); 

     return result; 
    } 

    public decimal Evaluate(string text, List<Variable> variables) 
    { 
     foreach (Variable v in variables) 
     { 
      text = text.Replace(v.Name, v.Value.ToString()); 
     } 

     return Evaluate(text); 
    } 

    private static bool EquationHasVariables(string equation) 
    { 
     Regex letters = new Regex(@"[A-Za-z]"); 

     return letters.IsMatch(equation); 
    } 

    private void SetVariables() 
    { 
     Regex letters = new Regex(@"([A-Za-z]+)"); 
     Variable v; 

     foreach (Match m in letters.Matches(equation, 0)) 
     { 
      v = new Variable(m.Groups[1].Value, decimal.Zero); 

      if (!variables.ContainsKey(v.Name)) 
      { 
       variables.Add(v.Name, v); 
      } 
     } 
    } 

    #region Parse V2 

    private Dictionary<string, string> parenthesesText = new Dictionary<string, string>(); 

    /* 
    * 1. All the text in first-level parentheses is replaced with replaceText plus an index value. 
    *  (All nested parentheses are parsed in recursive calls) 
    * 2. The simple function is parsed given the order of operations (reverse priority to 
    *  keep the order of operations correct when evaluating). 
    *  a. Addition (+), subtraction (-)     -> left to right 
    *  b. Multiplication (*), division (/), modulo (%) -> left to right 
    *  c. Exponents (^)         -> right to left 
    *  d. Factorials (!)         -> left to right 
    *  e. No op (number, replaced parentheses) 
    * 3. When an op is found, a two recursive calls are generated -- parsing the LHS and 
    *  parsing the RHS. 
    * 4. An EvalNode representing the root node of the evaluations tree is returned. 
    * 
    * Ex. 3 + 5     (3 + 5) * 8 
    *   +       * 
    *  /\      /\ 
    *   3 5      + 8 
    *         /\ 
    *  3 + 5 * 8     3 5 
    *   + 
    *   /\ 
    *   3 * 
    *   /\ 
    *   5 8 
    */ 

    /// <summary> 
    /// Parses the expression and returns the root node of a tree. 
    /// </summary> 
    /// <param name="eq">Equation to be parsed</param> 
    /// <param name="replaceText">Text base that replaces text in parentheses</param> 
    /// <returns></returns> 
    private EvalNode Parse(string eq, string replaceText) 
    { 
     int randomKeyIndex = 0; 

     eq = eq.Replace(" ", ""); 
     if (eq.Length == 0) 
     { 
      return new ValueNode(decimal.Zero); 
     } 

     int leftParentIndex = -1; 
     int rightParentIndex = -1; 
     SetIndexes(eq, ref leftParentIndex, ref rightParentIndex); 

     //remove extraneous outer parentheses 
     while (leftParentIndex == 0 && rightParentIndex == eq.Length - 1) 
     { 
      eq = eq.Substring(1, eq.Length - 2); 
      SetIndexes(eq, ref leftParentIndex, ref rightParentIndex); 
     } 

     //Pull out all expressions in parentheses 
     replaceText = GetNextReplaceText(replaceText, randomKeyIndex); 

     while (leftParentIndex != -1 && rightParentIndex != -1) 
     { 
      //replace the string with a random set of characters, stored extracted text in dictionary keyed on the random set of chars 

      string p = eq.Substring(leftParentIndex, rightParentIndex - leftParentIndex + 1); 
      eq = eq.Replace(p, replaceText); 
      parenthesesText.Add(replaceText, p); 

      leftParentIndex = 0; 
      rightParentIndex = 0; 

      replaceText = replaceText.Remove(replaceText.LastIndexOf(randomKeyIndex.ToString())); 
      randomKeyIndex++; 
      replaceText = GetNextReplaceText(replaceText, randomKeyIndex); 

      SetIndexes(eq, ref leftParentIndex, ref rightParentIndex); 
     } 

     /* 
     * Be sure to implement these operators in the function node class 
     */ 
     char[] ops_order0 = new char[2] { '+', '-' }; 
     char[] ops_order1 = new char[3] { '*', '/', '%' }; 
     char[] ops_order2 = new char[1] { '^' }; 
     char[] ops_order3 = new char[1] { '!' }; 

     /* 
     * In order to evaluate nodes LTR, the right-most node must be the root node 
     * of the tree, which is why we find the last index of LTR ops. The reverse 
     * is the case for RTL ops. 
     */ 

     int order0Index = eq.LastIndexOfAny(ops_order0); 

     if (order0Index > -1) 
     { 
      return CreateFunctionNode(eq, order0Index, replaceText + "0"); 
     } 

     int order1Index = eq.LastIndexOfAny(ops_order1); 

     if (order1Index > -1) 
     { 
      return CreateFunctionNode(eq, order1Index, replaceText + "0"); 
     } 

     int order2Index = eq.IndexOfAny(ops_order2); 

     if (order2Index > -1) 
     { 
      return CreateFunctionNode(eq, order2Index, replaceText + "0"); 
     } 

     int order3Index = eq.LastIndexOfAny(ops_order3); 

     if (order3Index > -1) 
     { 
      return CreateFunctionNode(eq, order3Index, replaceText + "0"); 
     } 

     //no operators... 
     eq = eq.Replace("(", ""); 
     eq = eq.Replace(")", ""); 

     if (char.IsLetter(eq[0])) 
     { 
      return Parse(parenthesesText[eq], replaceText + "0"); 
     } 

     return new ValueNode(decimal.Parse(eq)); 
    } 

    private string GetNextReplaceText(string replaceText, int randomKeyIndex) 
    { 
     while (parenthesesText.ContainsKey(replaceText)) 
     { 
      replaceText = replaceText + randomKeyIndex.ToString(); 
     } 
     return replaceText; 
    } 

    private EvalNode CreateFunctionNode(string eq, int index, string randomKey) 
    { 
     FunctionNode func = new FunctionNode(); 
     func.Op = eq[index].ToString(); 
     func.Lhs = Parse(eq.Substring(0, index), randomKey); 
     func.Rhs = Parse(eq.Substring(index + 1), randomKey); 

     return func; 
    } 

    #endregion 

    /// <summary> 
    /// Find the first set of parentheses 
    /// </summary> 
    /// <param name="eq"></param> 
    /// <param name="leftParentIndex"></param> 
    /// <param name="rightParentIndex"></param> 
    private static void SetIndexes(string eq, ref int leftParentIndex, ref int rightParentIndex) 
    { 
     leftParentIndex = eq.IndexOf('('); 
     rightParentIndex = eq.IndexOf(')'); 
     int tempIndex = eq.IndexOf('(', leftParentIndex + 1); 

     while (tempIndex != -1 && tempIndex < rightParentIndex) 
     { 
      rightParentIndex = eq.IndexOf(')', rightParentIndex + 1); 
      tempIndex = eq.IndexOf('(', tempIndex + 1); 
     } 
    } 
} 

public struct Variable 
{ 
    public string Name; 
    public decimal Value; 

    public Variable(string n, decimal v) 
    { 
     Name = n; 
     Value = v; 
     } 
    } 
} 
+0

क्यों 'EvalNode' इंटरफेस नहीं बनाते? अभी भी +1 – pyon

+0

मूल्यांकन पर शुरुआती काम के साथ मैं बस कुछ कोड वापस करने के लिए चाहता था। कोड के विकास ने मुझे जो पोस्ट किया था उसे मिला और आप सही हैं, EvalNode को एक इंटरफ़ेस में बदला जा सकता है। –

+0

ब्रैकेट के साथ विफल रहता है। उदा।: '(1 + 3) + 2' –

1

एमएस में गतिशील क्वेरी लाइब्रेरी नामक एक नमूना है। यह LINQ टीम द्वारा गतिशील रूप से LINQ क्वेरीज़ बनाने के लिए प्रदान किया जाता है जैसे कि: मंद क्वेरी = नॉर्थविंड.प्रोडक्ट्स। ("श्रेणी आईडी = 2") आप यह देखने के लिए जांच सकते हैं कि यह प्राथमिक गणित क्षमताओं की पेशकश करता है या नहीं।

0

मैंने अपनी वेबसाइट पर एक अल्ट्रा कॉम्पैक्ट (1 कक्षा, < 10 कीबी) जावा मैथ इल्यूलेटर के लिए स्रोत पोस्ट किया है। यह सी # को पोर्ट करने के लिए तुच्छ होना चाहिए। वहाँ अन्य लोग हैं जो अधिक कर सकते हैं, लेकिन यह बहुत सक्षम है, और यह छोटा है।

संबंधित मुद्दे