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 }