动态表达式计算
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 }