首页 > 代码库 > 动态表达式计算
动态表达式计算
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 else141 {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 =http://www.mamicode.com/ Convert.ToDouble(left);154 double rightValue =http://www.mamicode.com/ 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 else192 {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 else226 {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 = http://www.mamicode.com/m.Groups[1].Value;239 string operatorStr = m.Groups[3].Value;240 string rightValue = http://www.mamicode.com/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*1248 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 else261 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 }
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。