昨天在园子里看到有园友,写了相同标题的一篇文章。重点讲的是中缀表达式转换为后缀表达式的算法,但是实现的四则运算 有bug。其实我没看之前也不懂什么是 中缀和后缀表达式,之前有用过js eval 内置函数,后边一想貌似C#中是没有这样的一个函数,加上自己也没事,就试着自己写了下 这个所谓的四则运算。
我没有研究计算机是怎么来进行四则运算的,我只是按自己的想法来实现 对 6-2*(5-3)+6/2*(6-3+3)/2 这样一个随意组合的四则运算表达式。
我的思路是样的:
<1> 先递归把表达式中的括号中的表达式给算出来,然后将值将之替换
1 #region 计算括号中的表达式 2 /// <summary> 3 /// 获取括号中的计算表达式 4 /// (递归) 5 /// </summary> 6 /// <param name="express"></param> 7 public void GetBraceExpress(ref string express) 8 { 9 int leftBraceMaxIndex = -1; 10 IList<int> rightBraceMinIndexs = new List<int>(); 11 for (int i = 0; i < express.Length; i++) 12 { 13 if (express[i].ToString() == "(") 14 { 15 leftBraceMaxIndex = i; 16 } 17 if (express[i].ToString() == ")") 18 { 19 rightBraceMinIndexs.Add(i); 20 } 21 } 22 if (leftBraceMaxIndex != -1 && rightBraceMinIndexs.Count > 0) 23 { 24 int rightBraceIndex = 0; 25 foreach (var item in rightBraceMinIndexs) 26 { 27 if (item > leftBraceMaxIndex) 28 { 29 rightBraceIndex = item; 30 break; 31 } 32 } 33 34 string braceExpress = express.Substring(leftBraceMaxIndex, rightBraceIndex - leftBraceMaxIndex + 1); 35 double result = CalcExpress(braceExpress.TrimStart('(').TrimEnd(')')); //计算()中的表达式 36 express = express.Replace(braceExpress, result.ToString()); //结果替换 ()表达式 37 if (express.IndexOf("(") != -1 && express.IndexOf(")") != -1) 38 { 39 GetBraceExpress(ref express); 40 return; 41 } 42 } 43 } 44 #endregion 45 46 #region 计算表达式 47 /// <summary> 48 /// 计算表达式 49 /// </summary> 50 /// <param name="express">表达式</param> 51 /// <returns>表达式结果</returns> 52 public double CalcExpress(string express) 53 { 54 List<double> numbers = new List<double>(); //表达式中的数字 55 List<char> operaters = new List<char>(); //表达式中的操作符 56 int tempIndex = 0; 57 for (int i = 0; i < express.Length; i++) 58 { 59 if (!char.IsNumber(express[i]) && char.IsNumber(express[i - 1]) && i > 0) 60 { 61 if (tempIndex != 0) 62 tempIndex = tempIndex + 1; 63 numbers.Add(double.Parse(express.Substring(tempIndex, i - tempIndex))); 64 operaters.Add(express[i]); 65 tempIndex = i; 66 } 67 } 68 numbers.Add(double.Parse(express.Substring(tempIndex + 1, express.Length - tempIndex - 1))); 69 //开始计算 70 double result = 0; 71 if (operaters.Count == 0) 72 { 73 return double.Parse(express); 74 } 75 else 76 { 77 CalcMultiplyDivide(numbers, operaters); //计算乘除 78 result = CalcAddSubduction(numbers, operaters); //计算加减 79 } 80 return result; 81 } 82 #endregion
<2> 递归将 没有括号的表达式中的乘除计算,将结果替换 乘除表达式
1 #region 计算乘除 2 /// <summary> 3 /// 递归计算表达式中的乘/除运算 4 /// </summary> 5 /// <param name="numbers">表达式中的数字集合</param> 6 /// <param name="operaters">操作符集合</param> 7 public void CalcMultiplyDivide(List<double> numbers, List<char> operaters) 8 { 9 for (int i = 0; i < operaters.Count; i++) 10 { 11 bool temp = false; 12 double n = 0; 13 if (operaters[i] == '*') 14 { 15 n = numbers[i] * numbers[i + 1]; 16 temp = true; 17 } 18 else if (operaters[i] == '/') 19 { 20 n = numbers[i] / numbers[i + 1]; 21 temp = true; 22 } 23 if (temp) 24 { 25 operaters.RemoveAt(i); 26 numbers.RemoveRange(i, 2); 27 numbers.Insert(i, n); 28 CalcMultiplyDivide(numbers, operaters); 29 break; 30 } 31 } 32 } 33 #endregion
<3> 递归算加减,直到表达式中没有操作符,然后返回结果。
1 #region 计算加减 2 /// <summary> 3 /// 递归计算加减 4 /// </summary> 5 /// <param name="numbers">表达式中的数字集合</param> 6 /// <param name="operaters">操作符集合</param> 7 /// <returns>计算的结果</returns> 8 public double CalcAddSubduction(List<double> numbers, List<char> operaters) 9 { 10 11 for (int i = 0; i < operaters.Count; i++) 12 { 13 bool temp = false; 14 double n = 0; 15 if (operaters[i] == '+') 16 { 17 n = numbers[i] + numbers[i + 1]; 18 temp = true; 19 } 20 else if (operaters[i] == '-') 21 { 22 n = numbers[i] - numbers[i + 1]; 23 temp = true; 24 } 25 if (temp) 26 { 27 operaters.RemoveAt(i); 28 numbers.RemoveRange(i, 2); 29 numbers.Insert(i, n); 30 CalcAddSubduction(numbers, operaters); 31 break; 32 } 33 } 34 double result = 0; 35 if (operaters.Count == 0) 36 result = numbers[0]; 37 return result; 38 } 39 #endregion
这就可以实现像js eval 方法一样对一个四则运算表达式 计算了。这只是按我自己的思路来实现的,没有考虑性能啊什么的,如大家有什么好的法子,一起讨论下。
附上demo:http://files.cnblogs.com/joey0210/Calc.rar