首页 > 学院 > 开发设计 > 正文

如何在C#中运行数学表达式字符串

2019-11-06 06:34:46
字体:
来源:转载
供稿:网友

转自:http://www.cnblogs.com/WindBlog/archive/2012/10/22/2733511.html

如何在C#中运行数学表达式字符串

方法1:利用DataTable中的Compute方法

1 string exPRession = "1+2*3";2 DataTable eval = new DataTable();object result = eval.Compute(expression, “”);

方法2:利用xPath表达式

复制代码
 1 publicstaticdoubleEvaluate(string expression) 2 { 3     return(double)newSystem.xml.XPath.XPathDocument 4     (newStringReader("<r/>")).CreateNavigator().Evaluate 5     (string.Format("number({0})",new 6     System.Text.RegularExpressions.Regex(@"([/+/-/*])") 7     .Replace(expression," ${1} ") 8     .Replace("/"," div ") 9     .Replace("%"," mod ")));10 }复制代码

方法3:在网上找了一个计算表达式的类库

复制代码
  1  /**/  2     /// <summary>  3     /// 动态求值  4     /// </summary>  5     public class Evaluator  6     {  7         /**/  8         /// <summary>  9         /// 计算结果,如果表达式出错则抛出异常 10         /// </summary> 11         /// <param name="statement">表达式,如"1+2+3+4"</param> 12         /// <returns>结果</returns> 13         public static object Eval(string statement) 14         { 15             if (statement.Trim() != string.Empty) 16             { 17                 Evaluator evaluator = new Evaluator(); 18                 return evaluator.GetFormulaResult(statement); 19             } 20             else 21             { 22                 return null; 23             } 24         } 25  26  27         private object GetFormulaResult(string s) 28         { 29             if (s == "") 30             { 31                 return null; 32             } 33             string S = BuildingRPN(s); 34  35             string tmp = ""; 36             System.Collections.Stack sk = new System.Collections.Stack(); 37  38             char c = ' '; 39             System.Text.StringBuilder Operand = new System.Text.StringBuilder(); 40             double x, y; 41             for (int i = 0; 42                 i < S.Length; 43                 i++) 44             { 45                 c = S[i]; 46                 //added c==',' for germany culture 47                 if (char.IsDigit(c) || c == '.' || c == ',') 48                 { 49                     //数据值收集. 50                     Operand.Append(c); 51                 } 52                 else if (c == ' ' && Operand.Length > 0) 53                 { 54                     #region 运算数转换 55                     try 56                     { 57                         tmp = Operand.ToString(); 58                         if (tmp.StartsWith("-"))//负数的转换一定要小心...它不被直接支持. 59                         { 60                             //现在我的算法里这个分支可能永远不会被执行. 61                             sk.Push(-((double)Convert.ToDouble(tmp.Substring(1, tmp.Length - 1)))); 62                         } 63                         else 64                         { 65                             sk.Push(Convert.ToDouble(tmp)); 66                         } 67                     } 68                     catch 69                     { 70                         return null; // 71                     } 72                     Operand = new System.Text.StringBuilder(); 73                     #endregion 74                 } 75                 else if (c == '+'//运算符处理.双目运算处理. 76                     || c == '-' 77                     || c == '*' 78                     || c == '/' 79                     || c == '%' 80                     || c == '^') 81                 { 82                     #region 双目运算 83                     if (sk.Count > 0)/*如果输入的表达式根本没有包含运算符.或是根本就是空串.这里的逻辑就有意义了.*/ 84                     { 85                         y = (double)sk.Pop(); 86                     } 87                     else 88                     { 89                         sk.Push(0); 90                         break; 91                     } 92                     if (sk.Count > 0) 93                         x = (double)sk.Pop(); 94                     else 95                     { 96                         sk.Push(y); 97                         break; 98                     } 99                     switch (c)100                     {101                         case '+':102                             sk.Push(x + y);103                             break;104                         case '-':105                             sk.Push(x - y);106                             break;107                         case '*':108                             if (y == 0)109                             {110                                 sk.Push(x * 1);111                             }112                             else113                             {114                                 sk.Push(x * y);115                             }116                             break;117                         case '/':118                             if (y == 0)119                             {120                                 sk.Push(x / 1);121                             }122                             else123                             {124                                 sk.Push(x / y);125                             }126                             break;127                         case '%':128                             sk.Push(x % y);129                             break;130                         case '^'://131                             if (x > 0)//132                             {133                                 //我原本还想,如果被计算的数是负数,又要开真分数次方时如何处理的问题.后来我想还是算了吧.134                                 sk.Push(System.Math.Pow(x, y));135                                 //136                             }137                             //138                             else//139                             {140                                 //141                                 double t = y;142                                 //143                                 string ts = "";144                                 //145                                 t = 1 / (2 * t);146                                 //147                                 ts = t.ToString();148                                 //149                                 if (ts.ToUpper().LastIndexOf('E') > 0)//150                                 {151                                     //152                                     ;153                                     //154                                 }155                                 //156                             }157                             break;158                     }159                     #endregion160                 }161                 else if (c == '!')//单目取反. )162                 {163                     sk.Push(-((double)sk.Pop()));164                 }165             }166             if (sk.Count > 1)167             {168                 return null;//;169             }170             if (sk.Count == 0)171             {172                 return null;//;173             }174             return sk.Pop();175         }176         /**/177         /// <summary>178         /// 179         /// </summary>180         private string BuildingRPN(string s)181         {182             System.Text.StringBuilder sb = new System.Text.StringBuilder(s);183             System.Collections.Stack sk = new System.Collections.Stack();184             System.Text.StringBuilder re = new System.Text.StringBuilder();185 186             char c = ' ';187             //sb.Replace( " ","" );188             //一开始,我只去掉了空格.后来我不想不支持函数和常量能滤掉的全OUT掉.189             for (int i = 0;190                 i < sb.Length;191                 i++)192             {193                 c = sb[i];194                 //added c==',' for german culture195                 if (char.IsDigit(c) || c == ',')//数字当然要了.196                     re.Append(c);197                 //if( char.IsWhiteSpace( c )||198                 char.IsLetter(c);//如果是空白,那么不要.现在字母也不要.199                 //continue;200                 switch (c)//如果是其它字符...列出的要,没有列出的不要.201                 {202                     case '+':203                     case '-':204                     case '*':205                     case '/':206                     case '%':207                     case '^':208                     case '!':209                     case '(':210                     case ')':211                     case '.':212                         re.Append(c);213                         break;214                     default:215                         continue;216                 }217             }218             sb = new System.Text.StringBuilder(re.ToString());219             #region 对负号进行预转义处理.负号变单目运算符求反.220             for (int i = 0; i < sb.Length - 1; i++)221                 if (sb[i] == '-' && (i == 0 || sb[i - 1] == '('))222                     sb[i] = '!';223             //字符转义.224             #endregion225             #region 将中缀表达式变为后缀表达式.226             re = new System.Text.StringBuilder();227             for (int i = 0;228                 i < sb.Length;229                 i++)230             {231                 if (char.IsDigit(sb[i]) || sb[i] == '.')//如果是数值.232                 {233                     re.Append(sb[i]);234                     //加入后缀式235                 }236                 else if (sb[i] == '+'237                     || sb[i] == '-'238                     || sb[i] == '*'239                     || sb[i] == '/'240                     || sb[i] == '%'241                     || sb[i] == '^'242                     || sb[i] == '!')//.243                 {244                     #region 运算符处理245                     while (sk.Count > 0) //栈不为空时246                     {247                         c = (char)sk.Pop();248                         //将栈中的操作符弹出.249                         if (c == '(') //如果发现左括号.停.250                         {251                             sk.Push(c);252                             //将弹出的左括号压回.因为还有右括号要和它匹配.253                             break;254                             //中断.255                         }256                         else257                         {258                             if (Power(c) < Power(sb[i]))//如果优先级比上次的高,则压栈.259                             {260                                 sk.Push(c);261                                 break;262                             }263                             else264                             {265                                 re.Append(' ');266                                 re.Append(c);267                             }268                             //如果不是左括号,那么将操作符加入后缀式中.269                         }270                     }271                     sk.Push(sb[i]);272                     //把新操作符入栈.273                     re.Append(' ');274                     #endregion275                 }276                 else if (sb[i] == '(')//基本优先级提升277                 {278                     sk.Push('(');279                     re.Append(' ');280                 }281                 else if (sb[i] == ')')//基本优先级下调282                 {283                     while (sk.Count > 0) //栈不为空时284                     {285                         c = (char)sk.Pop();286                         //pop Operator287                         if (c != '(')288                         {289                             re.Append(' ');290                             re.Append(c);291                             //加入空格主要是为了防止不相干的数据相临产生解析错误.292                             re.Append(' ');293                         }294                         else295                             break;296                     }297                 }298                 else299                     re.Append(sb[i]);300             }301             while (sk.Count > 0)//这是最后一个弹栈啦.302             {303                 re.Append(' ');304                 re.Append(sk.Pop());305             }306             #endregion307             re.Append(' ');308             return FormatSpace(re.ToString());309             //在这里进行一次表达式格式化.这里就是后缀式了.  310         }311 312         /// <summary>  313         /// 优先级别测试函数.  314         /// </summary>  315         /// <param name="opr"></param>  316         /// <returns></returns>  317         private static int Power(char opr)318         {319             switch (opr)320             {321                 case '+':322                 case '-':323                     return 1;324                 case '*':325                 case '/':326                     return 2;327                 case '%':328                 case '^':329                 case '!':330                     return 3;331                 default:332                     return 0;333             }334         }335 336         /// <summary>  337         /// 规范化逆波兰表达式.338         /// </summary>  339         /// <param name="s"></param>  340         /// <returns></returns>  341         private static string FormatSpace(string s)342         {343             System.Text.StringBuilder ret = new System.Text.StringBuilder();344             for (int i = 0;345                 i < s.Length;346                 i++)347             {348                 if (!(s.Length > i + 1 && s[i] == ' ' && s[i + 1] == ' '))349                     ret.Append(s[i]);350                 else351                     ret.Append(s[i]);352             }353             return ret.ToString();354             //.Replace( '!','-' );355         }356     }

目前选用方法1,比较快捷,也暂时够用


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表