动态表达式计算

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 using System.Text.RegularExpressions;
  6 
  7 namespace CalcTest
  8 {
  9     public class CalculateExpress
 10     {
 11         //验证计算表达式 此正则只适用于C# 其他语言不支持
 12         private static Regex calcExpress = new Regex(@"^\s*-?(?>(?<k>\(\s*-)?(?:\d+(?:\.\d+)?|[a-z]+)(?(k)\)(?<-k>))(?=\s*(?:[-+*/%^)]|$))|(?<!(?:^|\()\s*)[+*/%^](?=\s*[(a-zA-Z0-9])|-(?=\s*[(a-zA-Z0-9])|\s+|(?:[A-Z]+)?\((?!\s*\))(?<Open>)|\)(?=\s*(?:[-+*/%^)]|$))(?<-Open>))*(?(Open)(?!))$",RegexOptions.IgnoreCase);
 13         private static Regex inBracket = new Regex(@"\(([0-9\+\-\*\/\.\^]+)\)");//匹配括号表达式
 14         private static Regex twoNumberPow = new Regex(@"\(?(-?\d+(\.\d+)?)\)?([\^])\(?(-?\d+(\.\d+)?)\)?");//幂运算表达式
 15         private static Regex twoNumberMD = new Regex(@"\(?(-?\d+(\.\d+)?)\)?([\*\/])\(?(-?\d+(\.\d+)?)\)?");//乘除运算表达式
 16         private static Regex twoNumberAE = new Regex(@"\(?(-?\d+(\.\d+)?)\)?([+-])\(?(-?\d+(\.\d+)?)\)?");//加减运算表达式
 17         private static Regex snRegex = new Regex(@"(-?\d+(\.\d+)?[Ee]\d+)");//科学计数法
 18         //自定义函数列表
 19         private IList<FunctionReflect> functions = new List<FunctionReflect>();
 20 
 21         public IList<string> listInfo = new List<string>();
 22 
 23         public IList<FunctionReflect> Functions
 24         {
 25             get { return functions; }
 26             set { functions = value; }
 27         }
 28 
 29         //函数委托
 30         public delegate string RunFunction(string[] args);
 31 
 32         //sin 正弦函数
 33         private string runFunctionSin(string[] args)
 34         {
 35             return Math.Sin(Convert.ToDouble(args[0])).ToString();
 36         }
 37 
 38         //cos 余弦函数
 39         private string runFunctionCos(string[] args)
 40         {
 41             return Math.Cos(Convert.ToDouble(args[0])).ToString();
 42         }
 43 
 44         //tan 正切函数
 45         private string runFunctionTan(string[] args)
 46         {
 47             return Math.Tan(Convert.ToDouble(args[0])).ToString();
 48         }
 49 
 50         //sqrt 开方函数
 51         private string runFunctionSqrt(string[] args)
 52         {
 53             return Math.Sqrt(Convert.ToDouble(args[0])).ToString();
 54         }
 55 
 56         //自定义函数类
 57         public class FunctionReflect
 58         {
 59             public FunctionReflect(Regex regx, RunFunction runFun)
 60             {
 61                 this.FunRegex = regx;
 62                 this.FunDelegate = runFun;
 63             }
 64 
 65             public FunctionReflect(string funname, RunFunction runFun)
 66             {
 67                 this.FunRegex = buildFunctionRegx(funname);
 68                 this.FunDelegate = runFun;
 69             }
 70 
 71             //自定义函数正则 用于计算时匹配表达式
 72             public Regex FunRegex { get; set; }
 73 
 74             //函数执行委托
 75             public RunFunction FunDelegate { get; set; }
 76 
 77             //根据函数名创建正则表达式 格式为 函数名(数字)
 78             private Regex buildFunctionRegx(string funName)
 79             {
 80                 string regex = funName + @"\(([0-9\+\-\*\/\.\^\(\)]+?)\)";
 81                 return new Regex(regex);
 82             }
 83         }
 84 
 85         //注册函数
 86         private void functionRegxRegister()
 87         {
 88             FunctionReflect funRef = null;
 89 
 90             funRef = new FunctionReflect("sin", runFunctionSin); functions.Add(funRef);
 91             funRef = new FunctionReflect("cos", runFunctionCos); functions.Add(funRef);
 92             funRef = new FunctionReflect("tan", runFunctionTan); functions.Add(funRef);
 93             funRef = new FunctionReflect("sqrt", runFunctionSqrt); functions.Add(funRef);
 94 
 95         }
 96 
 97         //判断是否存在自定义函数
 98         private bool hasFunction(string exp)
 99         {
100             bool result = false;
101             foreach (FunctionReflect fr in functions)
102             {
103                 if (fr.FunRegex.Match(exp).Success)
104                 {
105                     result = true;
106                     break;
107                 }
108             }
109             return result;
110         }
111 
112         //计算自定义函数
113         private string calcFunction(string exp)
114         {
115             Match m = null;
116             StringBuilder sbExpress = new StringBuilder(exp);
117             while (true)
118             {
119                 if (!hasFunction(sbExpress.ToString()))
120                     break;
121 
122                 foreach (FunctionReflect fr in functions)
123                 {
124                     while (true)
125                     {
126                         m = fr.FunRegex.Match(sbExpress.ToString());
127                         if (m.Success)
128                         {
129                             string repExp = m.Groups[0].Value;
130                             string[] calcExp = m.Groups[1].Value.Split(',');
131                             IList<string> args = new List<string>();
132                             foreach (string param in calcExp)
133                             {
134                                 args.Add(CalcSimpleExpress(param));
135                             }
136                             string result = fr.FunDelegate(args.ToArray());
137                             sbExpress = sbExpress.Replace(repExp, result, m.Index, m.Length);
138                             listInfo.Add(repExp + " 计算后 " + sbExpress.ToString());
139                         }
140                         else
141                         {
142                             break;
143                         }
144                     }
145                 }
146             }
147             return sbExpress.ToString();
148         }
149 
150         //计算两个数(+-*/^)的结果
151         private string calcTwoNumber(string left, string oper, string right)
152         {
153             double leftValue = Convert.ToDouble(left);
154             double rightValue = Convert.ToDouble(right);
155             switch (oper)
156             {
157                 case "+": return (leftValue + rightValue).ToString();
158                 case "-": return (leftValue - rightValue).ToString();
159                 case "*": return (leftValue * rightValue).ToString();
160                 case "/": return (leftValue / rightValue).ToString();
161                 case "^": return Math.Pow(leftValue, rightValue).ToString();
162                 default: return string.Empty;
163             }
164         }
165 
166         //将科学计数法表达式转化为数字
167         private string snToNormal(string sn)
168         {
169             sn = sn.ToLower().Trim();
170             string[] temp = sn.Split('e');
171             double l = Convert.ToDouble(temp[0]);
172             double r = Convert.ToDouble(temp[1]);
173             string result = (Math.Pow(10, r) * l).ToString();
174             return result;
175         }
176 
177         //替换表达式中的科学计数法表达式转化为数字
178         public string snReplace(string exp)
179         {
180             string express = exp.Trim();
181             StringBuilder sbExpress = new StringBuilder(express);
182             while (true)
183             {
184                 Match m = snRegex.Match(sbExpress.ToString());
185                 if (m.Success)
186                 {
187                     string sn = m.Groups[0].Value;
188                     sbExpress = sbExpress.Replace(sn, snToNormal(sn), m.Index, m.Length);
189                     listInfo.Add(sn + " 计算后 " + sbExpress.ToString());
190                 }
191                 else
192                 {
193                     break;
194                 }
195 
196             }
197 
198 
199             return sbExpress.ToString();
200         }
201 
202         //计算不带括号的表达式
203         private string calcExpressNoBracket(String exp)
204         {
205             Match m = null;
206             string express = exp;
207 
208             operationReplace(ref m, ref express, twoNumberPow);
209             operationReplace(ref m, ref express, twoNumberMD);
210             operationReplace(ref m, ref express, twoNumberAE);
211 
212             return express;
213         }
214 
215         //将表达式中的相邻的两个数计算出来(循环所有)
216         private void operationReplace(ref Match m, ref string express, Regex reg)
217         {
218             while (true)
219             {
220                 m = reg.Match(express);
221                 if (m.Success)
222                 {
223                     express = calcReplace(m, express);
224                 }
225                 else
226                 {
227                     break;
228                 }
229 
230             }
231         }
232 
233         //将表达式中的相邻的两个数计算出来(仅供operationReplace调用)
234         private string calcReplace(Match m, string express)
235         {
236             StringBuilder sbExpress = new StringBuilder(express);
237             string twoNumberExp = m.Groups[0].Value;
238             string leftValue = m.Groups[1].Value;
239             string operatorStr = m.Groups[3].Value;
240             string rightValue = m.Groups[4].Value;
241             string result = calcTwoNumber(leftValue, operatorStr, rightValue);
242             sbExpress = sbExpress.Replace(twoNumberExp, result, m.Index, m.Length);
243             listInfo.Add(twoNumberExp + " 计算后 " + sbExpress.ToString());
244             return sbExpress.ToString();
245         }
246 
247         // 计算括号内的表达式 如 1*(3-2) 的话就会把 3-2 计算出来 得到 1*1
248         private string clearBracket(string exp)
249         {
250             Match m = null;
251             StringBuilder sbExpress = new StringBuilder(exp);
252             while (true)
253             {
254                 m = inBracket.Match(sbExpress.ToString());
255                 if (m.Success)
256                 {
257                     sbExpress = sbExpress.Replace(m.Groups[0].Value, calcExpressNoBracket(m.Groups[1].Value), m.Index, m.Length);
258                     listInfo.Add(m.Groups[0].Value + " 计算后 " + sbExpress.ToString());
259                 }
260                 else
261                     break;
262             }
263             return sbExpress.ToString();
264         }
265 
266         //计算不带自定义函数的数学表达式(不能带科学计数法)
267         public string CalcSimpleExpress(string exp)
268         {
269             string express = exp.Trim();
270 
271             //先计算括号内的
272             express = clearBracket(express);
273 
274             //再计算括号外的
275             return calcExpressNoBracket(express);
276         }
277 
278         //计算不带自定义函数的数学表达式(不能带科学计数法)
279         public string CalcNoFunExpress(string exp)
280         {
281             string express = exp.Trim();
282 
283             //先计算括号内的
284             express = clearBracket(express);
285 
286             //再计算括号外的
287             return calcExpressNoBracket(express);
288         }
289 
290         //计算带自定义函数的数学表达式
291         public string CalcFunExpress(string exp)
292         {
293             //注册自定义函数
294             functionRegxRegister();
295 
296             string express = exp.Trim();
297 
298             //转换科学计数法
299             express = snReplace(express);
300 
301             //计算自定义函数
302             express = calcFunction(express);
303 
304             //计算最终结果
305             return CalcSimpleExpress(express);
306         }
307 
308         //验证数学表达式是否合法
309         public static bool RegexCalcExpress(string exp)
310         {
311             return calcExpress.IsMatch(exp.Trim());
312         }
313     }
314 }
View Code

 

posted @ 2014-06-19 09:23  stone87654321  阅读(331)  评论(0编辑  收藏  举报