数学表示试如:“2+(3/5+log(10)+exp(30)) + (5 +4/(-6))”
模型:
数学公式分为几个元素,
操作数 如:2 操作符 如:+ - * / 表达式:如(5 +4/(-6)) 或者数学方法log(10)
其实整个公式是一个表达式:
调用方式:
string mathexpstr = "2+5*5/6*30";
CalculaterExpression cc = new CalculaterExpression();
decimal result = cc.Calculate(mathexpstr);
以下是代码:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Reflection; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace Calculate 9 { 10 /****************************************************** 11 * 12 * Author: zgtian 13 * Data: 2016/04/08 14 * 15 * ***************************************************/ 16 17 18 19 /// <summary> 20 /// 表达式中负数必须用()括起来。比如 -1+2 修改为(-1)+2 在比如3/-2 改为 3/(-2), 21 /// 只支持单参数数学函数 比如log(200),暂不支持多参函数 比如 Atan2(a1,a2), 22 /// 例外:默认ln=log10(number) pow=pow(e,number) e=exp(1) 23 /// </summary> 24 public class CalculaterExpression 25 { 26 public decimal Calculate(string expressionString) 27 { 28 Expression exp = ConvertStringToExpressionObject(expressionString); 29 return Calculate(exp); 30 } 31 32 /// <summary> 33 /// 把字符串表达式转换成表达式类对象 34 /// </summary> 35 /// <param name="expressionString"></param> 36 /// <returns></returns> 37 private Expression ConvertStringToExpressionObject(string expressionString) 38 { 39 char[] chs = expressionString.ToCharArray(); 40 string str = expressionString.Substring(0, 1); 41 int startIndex = 0; 42 CharType preType = CharType.Unknown; 43 Expression expression = new Expression(); 44 45 for (int i = 0; i < chs.Length; i++) 46 { 47 CharType currentCharType = GetCharType(chs[i]); 48 if (currentCharType != preType) 49 { 50 if (preType == CharType.NUMBER) 51 { 52 str = expressionString.Substring(startIndex, i - startIndex); 53 Decimal number = 0; 54 decimal.TryParse(str, out number); 55 expression.Operands.Add(number); 56 startIndex = i; 57 preType = currentCharType; 58 } 59 else if (!(preType == CharType.CHAR && currentCharType == CharType.LeftBracket)) 60 { 61 startIndex = i; 62 preType = currentCharType; 63 } 64 } 65 66 switch (currentCharType) 67 { 68 case CharType.CHAR: 69 { 70 if (preType != CharType.CHAR) 71 { 72 startIndex = i; 73 preType = currentCharType; 74 } 75 } 76 break; 77 case CharType.ADD: 78 { 79 expression.Operators.Add(CalcOperator.ADD); 80 } 81 break; 82 case CharType.SUBTRACT: 83 { 84 expression.Operators.Add(CalcOperator.SUBTRACT); 85 } 86 break; 87 case CharType.MULTIPLY: 88 { 89 expression.Operators.Add(CalcOperator.MULTIPLY); 90 } 91 break; 92 case CharType.DIVIDE: 93 { 94 expression.Operators.Add(CalcOperator.DIVIDE); 95 } 96 break; 97 case CharType.LeftBracket: 98 { 99 Expression childExpression = new Expression(); 100 childExpression.parentExpression = expression; 101 expression.childExpression = childExpression; 102 expression = childExpression; 103 if (preType == CharType.CHAR) 104 { 105 str = expressionString.Substring(startIndex, i - startIndex).ToLower(); 106 str = str.Substring(0, 1).ToUpper() + str.Substring(1); 107 expression.FunctionName = str; 108 startIndex = i; 109 preType = currentCharType; 110 } 111 } 112 break; 113 case CharType.RightBracket: 114 { 115 expression.parentExpression.Operands.Add(expression); 116 expression = expression.parentExpression; 117 } 118 break; 119 case CharType.NUMBER: 120 break; 121 122 } 123 if (i == chs.Length - 1) 124 { 125 if (currentCharType == CharType.NUMBER) 126 { 127 str = expressionString.Substring(startIndex); 128 Decimal number = 0; 129 decimal.TryParse(str, out number); 130 expression.Operands.Add(number); 131 } 132 } 133 } 134 return expression; 135 } 136 137 /// <summary> 138 /// 计算表达式对象 139 /// </summary> 140 /// <param name="exp"></param> 141 /// <returns></returns> 142 private decimal Calculate(Expression exp) 143 { 144 decimal result = 0; 145 //先计算所有的表达式 146 for (int i = 0; i < exp.Operands.Count; i++) 147 { 148 if (typeof(Expression).IsInstanceOfType(exp.Operands[i])) 149 { 150 exp.Operands[i] = Calculate((Expression)exp.Operands[i]); 151 } 152 } 153 154 //计算乘除 155 for (int i = 0; i < exp.Operators.Count; i++) 156 { 157 CalcOperator ope = exp.Operators[i]; 158 if (ope == CalcOperator.MULTIPLY) 159 { 160 exp.Operands[i] = (decimal)exp.Operands[i] * (decimal)exp.Operands[i + 1]; 161 exp.Operands.Remove(exp.Operands[i + 1]); 162 exp.Operators.Remove(exp.Operators[i]); 163 i--; 164 } 165 else if (ope == CalcOperator.DIVIDE) 166 { 167 exp.Operands[i] = (decimal)exp.Operands[i] / (decimal)exp.Operands[i + 1]; 168 exp.Operands.Remove(exp.Operands[i + 1]); 169 exp.Operators.Remove(exp.Operators[i]); 170 i--; 171 } 172 } 173 174 //最后计算所有的加减法 175 for (int i = 0; i < exp.Operators.Count; i++) 176 { 177 //负数比如(-1),如果此时的操作符不为-减号则解析错误 178 if (exp.Operands.Count == 1) 179 { 180 exp.Operands[0] = 0 - (decimal)exp.Operands[0]; 181 break; 182 } 183 184 CalcOperator ope = exp.Operators[i]; 185 if (ope == CalcOperator.ADD) 186 { 187 exp.Operands[i] = (decimal)exp.Operands[i] + (decimal)exp.Operands[i + 1]; 188 } 189 else if (ope == CalcOperator.SUBTRACT) 190 { 191 exp.Operands[i] = (decimal)exp.Operands[i] - (decimal)exp.Operands[i + 1]; 192 } 193 else 194 { 195 throw new Exception("数学表达式解析错误,还有非加减的运算符:" + exp.Operands[i].ToString() + ope.ToString() + exp.Operands[i+1].ToString()); 196 } 197 exp.Operands.Remove(exp.Operands[i + 1]); 198 exp.Operators.Remove(exp.Operators[i]); 199 i--; 200 201 } 202 result = (decimal)exp.Operands[0]; 203 //如果表达式是数学方法,则调用数学方法 204 if (exp.Operators.Count == 0) 205 { 206 if (!string.IsNullOrEmpty(exp.FunctionName)) 207 { 208 result = CalcMathFunction(exp.FunctionName, (decimal)exp.Operands[0]); 209 exp.FunctionName = null; 210 } 211 } 212 return result; 213 } 214 215 /// <summary> 216 /// 数学方法,可以枚举出来,不必反射。 217 /// </summary> 218 /// <param name="functionName"></param> 219 /// <param name="value"></param> 220 /// <returns></returns> 221 private decimal CalcMathFunction(string functionName, decimal value) 222 { 223 try 224 { 225 if (functionName.ToLower() == "pow") 226 { 227 //项目需求唯一的一个需要2个参数的数学方法且底数固定为e Exp(1) 228 return Convert.ToDecimal(Math.Pow(Math.Exp(1), (double)value)); 229 } 230 231 if (functionName.ToLower() == "ln") 232 { 233 functionName = "Log10"; 234 } 235 MethodInfo[] mathMethods = typeof(Math).GetMethods(BindingFlags.Static | BindingFlags.InvokeMethod | BindingFlags.Public); 236 MethodInfo actureMethod = null; 237 for (int i = 0; i < mathMethods.Length; i++) 238 { 239 //只找一个参数的方法 240 if (mathMethods[i].Name == functionName && mathMethods[i].GetParameters().Length==1) 241 { 242 actureMethod = mathMethods[i]; 243 break; 244 } 245 } 246 247 Type parameterType = actureMethod.GetParameters()[0].ParameterType; 248 string parameterTypeName = parameterType.Name; 249 MethodInfo convertMethod = typeof(Convert).GetMethod("To" + parameterTypeName, new Type[] { typeof(decimal) }); 250 var parameter = convertMethod.Invoke(null, new object[] { value }); 251 var result = actureMethod.Invoke(null, new Object[] { parameter }); 252 return Convert.ToDecimal(result); 253 } 254 catch(Exception ex) 255 { 256 throw new Exception("数学方法错误,方法名:" + functionName + ",参数:" + value + "," + ex.StackTrace); 257 } 258 259 } 260 261 262 private bool IsNumber(char c) 263 { 264 if ((c >= 48 && c <= 57) || c == 46) 265 return true; 266 else 267 return false; 268 } 269 270 private bool IsOperator(char c) 271 { 272 bool result = false; 273 switch (c) 274 { 275 case ‘+‘: 276 case ‘-‘: 277 case ‘*‘: 278 case ‘/‘: 279 result = true; 280 break; 281 default: 282 break; 283 } 284 return result; 285 } 286 287 private bool IsCharacter(char c) 288 { 289 if ((c >= 65 && c <= 90) || (c >= 97 && c <= 122)) 290 { 291 return true; 292 } 293 return false; 294 } 295 296 297 private CharType GetCharType(char c) 298 { 299 switch (c) 300 { 301 case ‘+‘: 302 return CharType.ADD; 303 case ‘-‘: 304 return CharType.SUBTRACT; 305 case ‘*‘: 306 return CharType.MULTIPLY; 307 case ‘/‘: 308 return CharType.DIVIDE; 309 default: 310 break; 311 } 312 if (IsCharacter(c)) 313 return CharType.CHAR; 314 else if (IsNumber(c)) 315 return CharType.NUMBER; 316 else if (c == ‘(‘) 317 return CharType.LeftBracket; 318 else if (c == ‘)‘) 319 return CharType.RightBracket; 320 return CharType.Unknown; 321 } 322 323 private enum CharType 324 { 325 ADD,SUBTRACT,MULTIPLY,DIVIDE,NUMBER,CHAR,LeftBracket,RightBracket,Unknown 326 } 327 328 329 } 330 331 /// <summary> 332 /// 计算表达式 如()阔起来的、数学方法log(10) 333 /// </summary> 334 internal class Expression 335 { 336 private List<Object> operand = new List<object>(); 337 private List<CalcOperator> operators = new List<CalcOperator>(); 338 public Expression parentExpression = null; 339 public Expression childExpression = null; 340 341 /// <summary> 342 /// 只有当表达式为方法时才赋值 343 /// </summary> 344 public string FunctionName { get; set; } 345 346 public List<Object> Operands { get { return operand; } } 347 public List<CalcOperator> Operators { get { return operators; } } 348 } 349 350 /// <summary> 351 /// 操作符 352 /// </summary> 353 internal enum CalcOperator 354 { 355 ADD, SUBTRACT, MULTIPLY, DIVIDE 356 } 357 358 359 }
时间: 2024-10-15 10:59:14