转自: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,比较快捷,也暂时够用
新闻热点
疑难解答