利用System.Linq.Expressions实现四则运算计算器(二)
如何将数学表达式转换成表达式树?
上节提到用几个类来封装数学表达式,对于数学表达式“5*4/(3+2-1)”转换成表达式树后如下图:
其中“表达式列表”和“/(3+2-1)”都是使用BWExpressionNodeCollection表示,“5”、“*4”、“3”、“+2”、“-1”都是用BWConstantExpressionNode表示。
如何将数学表达式字符串转换成表达式树呢?答案就是使用正则表达式。
匹配数字的正则表达式是“"d+("."d+)?”,匹配符号的表达式是“("+|-|"*|/)”。匹配括号的正则表达式是“"([^"(")]*(((?'Open'"()[^"(")]*)+((?'-Open'"))[^"(")]*)+)*(?(Open)(?!))")”。具体正则表达式怎么写,怎么用,请大家在网上搜索下啦!
数学表达式中,第一个数字如果是负数,则可以直接写成“-2+3”,如果负数在表达式中间,则需要使用括号括起来“2*(-2)+3”。不管负数在哪里,都有一个规律,在前面总结的简单表达式中,负数总是第一个。所以程序在做转换的时候,只需要考虑第一个数字是负数的情况(括号里面负数也只能是第一个)。可以匹配负数的正则表达式是“-?"d+("."d+)?”。
生成表达式树,请看下面流程图:
生成表达式树的工作全部交给BWExpressionNodeCollection,我在设计BWExpressionNodeCollection类时,采用构造函数传入数学表达式字符串:
///<summary> ///表达式节点集合 ///</summary> ///<param name="input">表达式字符串</param> ///<param name="type">此表达式前的操作符</param> public BWExpressionNodeCollection(string input, BWExpressionNodeType type) { base.ExpressionNodeType = type; this.expressionString = input; this.expressionNodeList = new BWExpressionNodeList(); double? val = ParseNegative(); if (val.HasValue) { this.expressionNodeList.Add(new BWConstantExpressionNode(val.Value, BWExpressionNodeType.Start)); } else { string parenthesesContent = GetParentheses(); if (!String.IsNullOrEmpty(parenthesesContent)) { this.expressionNodeList.Add(new BWExpressionNodeCollection(parenthesesContent, BWExpressionNodeType.Start)); } else { throw Error.GenericException; } } while (!String.IsNullOrEmpty(this.expressionString)) { char? sign = GetSign(); if (sign.HasValue) { BWExpressionNodeType nextType; switch (sign) { case '+': nextType = BWExpressionNodeType.Addition; break; case '-': nextType = BWExpressionNodeType.Subtration; break; case '*': nextType = BWExpressionNodeType.Multiplication; break; case '/': nextType = BWExpressionNodeType.Division; break; default: throw Error.GenericException; } double? operand = ParsePositive(); if (operand.HasValue) { this.expressionNodeList.Add(new BWConstantExpressionNode(operand.Value, nextType)); } else { string parenthesesContent = GetParentheses(); if (!String.IsNullOrEmpty(parenthesesContent)) { this.expressionNodeList.Add(new BWExpressionNodeCollection(parenthesesContent, nextType)); } else { throw Error.GenericException; } } } else { throw Error.GenericException; } } } |
可以看到,如果数学表达式遇到括号,则把括号内的数学表达式生成一个子BWExpressionNodeCollection对象。
到此为止,表达式树就已经生成,生成方法就是:
string input = @"1 + 5 * 9 - ( 1 + 2 ) * 3 / 4 + 6 * ( -2 )"; BWExpressionNodeCollection nodes = new BWExpressionNodeCollection(input, BWExpressionNodeType.Start); |
接下来将介绍如何从表达式树生成System.Linq.Expressions下面的类。请大家留意!