字符串公式解析器——使用“逆波兰式算法”及C#实现
从5月中旬到7月中旬,我一直在做焊接工程中接头图的参数化和自动化生成软件。主要是将各种标准接头图分解为一个个的图元,并自定义图元参数和图参数,用户在使用时,只需修改相关参数值,即能生成其所需要的接头图,无须再人工用CAD软件手动绘画。如下图所示。
其中采用了自定义公式来描述参数的变化将导致的图形变化。例如对于厚度的变化,定义的公式为:“dotAll.x=dotAll.x*t1/dot1.y;dotAll.y=dotAll.y*t1/dot1.y;”。这个公式表示对于图形中的所有点,当厚度变化时,点的x坐标变为 原x坐标值乘以新的厚度,再除以原来的序号为1的点的y坐标(即原来的厚度),同理对于y坐标的变化也一样。
最终公式将解析成 x=2.0 * 3 / 1.5, 最终结果为 4.0。问题的焦点在于如何将“2.0 * 3 / 1.5”这种字符串的表达式,让计算机能理解,并计算出结果。这里我采用了“逆波兰式算法”来解决这个问题。
关于“逆波兰式算法”的具体内容,请看这里 http://baike.baidu.com/view/2582.htm ,里面解释得很好。
最终程序里面的算法描述如下 :
下面我们来具体实现下这个算法,代码中注释较全,就不详细解说了。
首先,我们来定义下操作数类。
定义操作数类型枚举
1 /// <summary>
2 /// 操作数类型
3 /// </summary>
4 public enum OperandType
5 {
6 /// <summary>
7 /// 函数
8 /// </summary>
9 FUNC = 1,
10
11 /// <summary>
12 /// 日期
13 /// </summary>
14 DATE = 2,
15
16 /// <summary>
17 /// 数字
18 /// </summary>
19 NUMBER = 3,
20
21 /// <summary>
22 /// 布尔
23 /// </summary>
24 BOOLEAN = 4,
25
26 /// <summary>
27 /// 字符串
28 /// </summary>
29 STRING = 5
30
31 }
2 /// 操作数类型
3 /// </summary>
4 public enum OperandType
5 {
6 /// <summary>
7 /// 函数
8 /// </summary>
9 FUNC = 1,
10
11 /// <summary>
12 /// 日期
13 /// </summary>
14 DATE = 2,
15
16 /// <summary>
17 /// 数字
18 /// </summary>
19 NUMBER = 3,
20
21 /// <summary>
22 /// 布尔
23 /// </summary>
24 BOOLEAN = 4,
25
26 /// <summary>
27 /// 字符串
28 /// </summary>
29 STRING = 5
30
31 }
操作数类 Operand
1 public class Operand
2 {
3 #region Constructed Function
4 public Operand(OperandType type, object value)
5 {
6 this.Type = type;
7 this.Value = value;
8 }
9
10 public Operand(string opd, object value)
11 {
12 this.Type = ConvertOperand(opd);
13 this.Value = value;
14 }
15 #endregion
16
17 #region Variable & Property
18 /// <summary>
19 /// 操作数类型
20 /// </summary>
21 public OperandType Type { get; set; }
22
23 /// <summary>
24 /// 关键字
25 /// </summary>
26 public string Key { get; set; }
27
28 /// <summary>
29 /// 操作数值
30 /// </summary>
31 public object Value { get; set; }
32
33 #endregion
34
35 #region Public Method
36 /// <summary>
37 /// 转换操作数到指定的类型
38 /// </summary>
39 /// <param name="opd">操作数</param>
40 /// <returns>返回对应的操作数类型</returns>
41 public static OperandType ConvertOperand(string opd)
42 {
43 if (opd.IndexOf("(") > -1)
44 {
45 return OperandType.FUNC;
46 }
47 else if (IsNumber(opd))
48 {
49 return OperandType.NUMBER;
50 }
51 else if (IsDate(opd))
52 {
53 return OperandType.DATE;
54 }
55 else
56 {
57 return OperandType.STRING;
58 }
59 }
60
61 /// <summary>
62 /// 判断对象是否为数字
63 /// </summary>
64 /// <param name="value">对象值</param>
65 /// <returns>是返回真,否返回假</returns>
66 public static bool IsNumber(object value)
67 {
68 double val;
69 return double.TryParse(value.ToString(), out val);
70 }
71
72 /// <summary>
73 /// 判断对象是否为日期
74 /// </summary>
75 /// <param name="value">对象值</param>
76 /// <returns>是返回真,否返回假</returns>
77 public static bool IsDate(object value)
78 {
79 DateTime dt;
80 return DateTime.TryParse(value.ToString(), out dt);
81 }
82 #endregion
83 }
2 {
3 #region Constructed Function
4 public Operand(OperandType type, object value)
5 {
6 this.Type = type;
7 this.Value = value;
8 }
9
10 public Operand(string opd, object value)
11 {
12 this.Type = ConvertOperand(opd);
13 this.Value = value;
14 }
15 #endregion
16
17 #region Variable & Property
18 /// <summary>
19 /// 操作数类型
20 /// </summary>
21 public OperandType Type { get; set; }
22
23 /// <summary>
24 /// 关键字
25 /// </summary>
26 public string Key { get; set; }
27
28 /// <summary>
29 /// 操作数值
30 /// </summary>
31 public object Value { get; set; }
32
33 #endregion
34
35 #region Public Method
36 /// <summary>
37 /// 转换操作数到指定的类型
38 /// </summary>
39 /// <param name="opd">操作数</param>
40 /// <returns>返回对应的操作数类型</returns>
41 public static OperandType ConvertOperand(string opd)
42 {
43 if (opd.IndexOf("(") > -1)
44 {
45 return OperandType.FUNC;
46 }
47 else if (IsNumber(opd))
48 {
49 return OperandType.NUMBER;
50 }
51 else if (IsDate(opd))
52 {
53 return OperandType.DATE;
54 }
55 else
56 {
57 return OperandType.STRING;
58 }
59 }
60
61 /// <summary>
62 /// 判断对象是否为数字
63 /// </summary>
64 /// <param name="value">对象值</param>
65 /// <returns>是返回真,否返回假</returns>
66 public static bool IsNumber(object value)
67 {
68 double val;
69 return double.TryParse(value.ToString(), out val);
70 }
71
72 /// <summary>
73 /// 判断对象是否为日期
74 /// </summary>
75 /// <param name="value">对象值</param>
76 /// <returns>是返回真,否返回假</returns>
77 public static bool IsDate(object value)
78 {
79 DateTime dt;
80 return DateTime.TryParse(value.ToString(), out dt);
81 }
82 #endregion
83 }
然后,我们来定义下运算符类。
运算符类型枚举
1 /// <summary>
2 /// 运算符类型(从上到下优先级依次递减),数值越大,优先级越低
3 /// </summary>
4 public enum OperatorType
5 {
6 /// <summary>
7 /// 左括号:(,left bracket
8 /// </summary>
9 LB = 10,
10
11 /// <summary>
12 /// 右括号),right bracket
13 /// </summary>
14 RB = 11,
15
16 /// <summary>
17 /// 逻辑非,!,NOT
18 /// </summary>
19 NOT = 20,
20
21 /// <summary>
22 /// 正号,+,positive sign
23 /// </summary>
24 PS = 21,
25
26 /// <summary>
27 /// 负号,-,negative sign
28 /// </summary>
29 NS = 22,
30
31 /// <summary>
32 /// 正切,tan
33 /// </summary>
34 TAN = 23,
35 /// <summary>
36 /// 反正切,atan
37 /// </summary>
38 ATAN = 24,
39
40
41 /// <summary>
42 /// 乘,*,multiplication
43 /// </summary>
44 MUL = 30,
45
46 /// <summary>
47 /// 除,/,division
48 /// </summary>
49 DIV = 31,
50
51 /// <summary>
52 /// 余,%,modulus
53 /// </summary>
54 MOD = 32,
55
56 /// <summary>
57 /// 加,+,Addition
58 /// </summary>
59 ADD = 40,
60
61 /// <summary>
62 /// 减,-,subtraction
63 /// </summary>
64 SUB = 41,
65
66 /// <summary>
67 /// 小于,less than
68 /// </summary>
69 LT = 50,
70
71 /// <summary>
72 /// 小于或等于,less than or equal to
73 /// </summary>
74 LE = 51,
75
76 /// <summary>
77 /// 大于,>,greater than
78 /// </summary>
79 GT = 52,
80
81 /// <summary>
82 /// 大于或等于,>=,greater than or equal to
83 /// </summary>
84 GE = 53,
85
86 /// <summary>
87 /// 等于,=,equal to
88 /// </summary>
89 ET = 60,
90
91 /// <summary>
92 /// 不等于,unequal to
93 /// </summary>
94 UT = 61,
95
96 /// <summary>
97 /// 逻辑与,&,AND
98 /// </summary>
99 AND = 70,
100
101 /// <summary>
102 /// 逻辑或,|,OR
103 /// </summary>
104 OR = 71,
105
106 /// <summary>
107 /// 逗号,comma
108 /// </summary>
109 CA = 80,
110
111 /// <summary>
112 /// 结束符号 @
113 /// </summary>
114 END = 255,
115
116 /// <summary>
117 /// 错误符号
118 /// </summary>
119 ERR = 256
120
121 }
2 /// 运算符类型(从上到下优先级依次递减),数值越大,优先级越低
3 /// </summary>
4 public enum OperatorType
5 {
6 /// <summary>
7 /// 左括号:(,left bracket
8 /// </summary>
9 LB = 10,
10
11 /// <summary>
12 /// 右括号),right bracket
13 /// </summary>
14 RB = 11,
15
16 /// <summary>
17 /// 逻辑非,!,NOT
18 /// </summary>
19 NOT = 20,
20
21 /// <summary>
22 /// 正号,+,positive sign
23 /// </summary>
24 PS = 21,
25
26 /// <summary>
27 /// 负号,-,negative sign
28 /// </summary>
29 NS = 22,
30
31 /// <summary>
32 /// 正切,tan
33 /// </summary>
34 TAN = 23,
35 /// <summary>
36 /// 反正切,atan
37 /// </summary>
38 ATAN = 24,
39
40
41 /// <summary>
42 /// 乘,*,multiplication
43 /// </summary>
44 MUL = 30,
45
46 /// <summary>
47 /// 除,/,division
48 /// </summary>
49 DIV = 31,
50
51 /// <summary>
52 /// 余,%,modulus
53 /// </summary>
54 MOD = 32,
55
56 /// <summary>
57 /// 加,+,Addition
58 /// </summary>
59 ADD = 40,
60
61 /// <summary>
62 /// 减,-,subtraction
63 /// </summary>
64 SUB = 41,
65
66 /// <summary>
67 /// 小于,less than
68 /// </summary>
69 LT = 50,
70
71 /// <summary>
72 /// 小于或等于,less than or equal to
73 /// </summary>
74 LE = 51,
75
76 /// <summary>
77 /// 大于,>,greater than
78 /// </summary>
79 GT = 52,
80
81 /// <summary>
82 /// 大于或等于,>=,greater than or equal to
83 /// </summary>
84 GE = 53,
85
86 /// <summary>
87 /// 等于,=,equal to
88 /// </summary>
89 ET = 60,
90
91 /// <summary>
92 /// 不等于,unequal to
93 /// </summary>
94 UT = 61,
95
96 /// <summary>
97 /// 逻辑与,&,AND
98 /// </summary>
99 AND = 70,
100
101 /// <summary>
102 /// 逻辑或,|,OR
103 /// </summary>
104 OR = 71,
105
106 /// <summary>
107 /// 逗号,comma
108 /// </summary>
109 CA = 80,
110
111 /// <summary>
112 /// 结束符号 @
113 /// </summary>
114 END = 255,
115
116 /// <summary>
117 /// 错误符号
118 /// </summary>
119 ERR = 256
120
121 }
运算符类
public class Operator
{
public Operator(OperatorType type, string value)
{
this.Type = type;
this.Value = value;
}
/// <summary>
/// 运算符类型
/// </summary>
public OperatorType Type { get; set; }
/// <summary>
/// 运算符值
/// </summary>
public string Value { get; set; }
/// <summary>
/// 对于>或者<运算符,判断实际是否为>=,<>、<=,并调整当前运算符位置
/// </summary>
/// <param name="currentOpt">当前运算符</param>
/// <param name="currentExp">当前表达式</param>
/// <param name="currentOptPos">当前运算符位置</param>
/// <param name="adjustOptPos">调整后运算符位置</param>
/// <returns>返回调整后的运算符</returns>
public static string AdjustOperator(string currentOpt, string currentExp, ref int currentOptPos)
{
switch (currentOpt)
{
case "<":
if (currentExp.Substring(currentOptPos, 2) == "<=")
{
currentOptPos++;
return "<=";
}
if (currentExp.Substring(currentOptPos, 2) == "<>")
{
currentOptPos++;
return "<>";
}
return "<";
case ">":
if (currentExp.Substring(currentOptPos, 2) == ">=")
{
currentOptPos++;
return ">=";
}
return ">";
case "t":
if (currentExp.Substring(currentOptPos, 3) == "tan")
{
currentOptPos += 2;
return "tan";
}
return "error";
case "a":
if (currentExp.Substring(currentOptPos, 4) == "atan")
{
currentOptPos += 3;
return "atan";
}
return "error";
default:
return currentOpt;
}
}
/// <summary>
/// 转换运算符到指定的类型
/// </summary>
/// <param name="opt">运算符</param>
/// <param name="isBinaryOperator">是否为二元运算符</param>
/// <returns>返回指定的运算符类型</returns>
public static OperatorType ConvertOperator(string opt, bool isBinaryOperator)
{
switch (opt)
{
case "!": return OperatorType.NOT;
case "+": return isBinaryOperator ? OperatorType.ADD : OperatorType.PS;
case "-": return isBinaryOperator ? OperatorType.SUB : OperatorType.NS;
case "*": return isBinaryOperator ? OperatorType.MUL : OperatorType.ERR;
case "/": return isBinaryOperator ? OperatorType.DIV : OperatorType.ERR;
case "%": return isBinaryOperator ? OperatorType.MOD : OperatorType.ERR;
case "<": return isBinaryOperator ? OperatorType.LT : OperatorType.ERR;
case ">": return isBinaryOperator ? OperatorType.GT : OperatorType.ERR;
case "<=": return isBinaryOperator ? OperatorType.LE : OperatorType.ERR;
case ">=": return isBinaryOperator ? OperatorType.GE : OperatorType.ERR;
case "<>": return isBinaryOperator ? OperatorType.UT : OperatorType.ERR;
case "=": return isBinaryOperator ? OperatorType.ET : OperatorType.ERR;
case "&": return isBinaryOperator ? OperatorType.AND : OperatorType.ERR;
case "|": return isBinaryOperator ? OperatorType.OR : OperatorType.ERR;
case ",": return isBinaryOperator ? OperatorType.CA : OperatorType.ERR;
case "@": return isBinaryOperator ? OperatorType.END : OperatorType.ERR;
default: return OperatorType.ERR;
}
}
/// <summary>
/// 转换运算符到指定的类型
/// </summary>
/// <param name="opt">运算符</param>
/// <returns>返回指定的运算符类型</returns>
public static OperatorType ConvertOperator(string opt)
{
switch (opt)
{
case "!": return OperatorType.NOT;
case "+": return OperatorType.ADD;
case "-": return OperatorType.SUB;
case "*": return OperatorType.MUL;
case "/": return OperatorType.DIV;
case "%": return OperatorType.MOD;
case "<": return OperatorType.LT;
case ">": return OperatorType.GT;
case "<=": return OperatorType.LE;
case ">=": return OperatorType.GE;
case "<>": return OperatorType.UT;
case "=": return OperatorType.ET;
case "&": return OperatorType.AND;
case "|": return OperatorType.OR;
case ",": return OperatorType.CA;
case "@": return OperatorType.END;
case "tan": return OperatorType.TAN;
case "atan": return OperatorType.ATAN;
default: return OperatorType.ERR;
}
}
/// <summary>
/// 运算符是否为二元运算符,该方法有问题,暂不使用
/// </summary>
/// <param name="tokens">语法单元堆栈</param>
/// <param name="operators">运算符堆栈</param>
/// <param name="currentOpd">当前操作数</param>
/// <returns>是返回真,否返回假</returns>
public static bool IsBinaryOperator(ref Stack<object> tokens, ref Stack<Operator> operators, string currentOpd)
{
if (currentOpd != "")
{
return true;
}
else
{
object token = tokens.Peek();
if (token is Operand)
{
if (operators.Peek().Type != OperatorType.LB)
{
return true;
}
else
{
return false;
}
}
else
{
if (((Operator)token).Type == OperatorType.RB)
{
return true;
}
else
{
return false;
}
}
}
}
/// <summary>
/// 运算符优先级比较
/// </summary>
/// <param name="optA">运算符类型A</param>
/// <param name="optB">运算符类型B</param>
/// <returns>A与B相比,-1,低;0,相等;1,高</returns>
public static int ComparePriority(OperatorType optA, OperatorType optB)
{
if (optA == optB)
{
//A、B优先级相等
return 0;
}
//乘,除,余(*,/,%)
if ((optA >= OperatorType.MUL && optA <= OperatorType.MOD) &&
(optB >= OperatorType.MUL && optB <= OperatorType.MOD))
{
return 0;
}
//加,减(+,-)
if ((optA >= OperatorType.ADD && optA <= OperatorType.SUB) &&
(optB >= OperatorType.ADD && optB <= OperatorType.SUB))
{
return 0;
}
//小于,小于或等于,大于,大于或等于(<,<=,>,>=)
if ((optA >= OperatorType.LT && optA <= OperatorType.GE) &&
(optB >= OperatorType.LT && optB <= OperatorType.GE))
{
return 0;
}
//等于,不等于(=,<>)
if ((optA >= OperatorType.ET && optA <= OperatorType.UT) &&
(optB >= OperatorType.ET && optB <= OperatorType.UT))
{
return 0;
}
//三角函数
if ((optA>=OperatorType.TAN && optA<=OperatorType.ATAN)&&
(optB >= OperatorType.TAN && optB <= OperatorType.ATAN))
{
return 0;
}
if (optA < optB)
{
//A优先级高于B
return 1;
}
//A优先级低于B
return -1;
}
}
{
public Operator(OperatorType type, string value)
{
this.Type = type;
this.Value = value;
}
/// <summary>
/// 运算符类型
/// </summary>
public OperatorType Type { get; set; }
/// <summary>
/// 运算符值
/// </summary>
public string Value { get; set; }
/// <summary>
/// 对于>或者<运算符,判断实际是否为>=,<>、<=,并调整当前运算符位置
/// </summary>
/// <param name="currentOpt">当前运算符</param>
/// <param name="currentExp">当前表达式</param>
/// <param name="currentOptPos">当前运算符位置</param>
/// <param name="adjustOptPos">调整后运算符位置</param>
/// <returns>返回调整后的运算符</returns>
public static string AdjustOperator(string currentOpt, string currentExp, ref int currentOptPos)
{
switch (currentOpt)
{
case "<":
if (currentExp.Substring(currentOptPos, 2) == "<=")
{
currentOptPos++;
return "<=";
}
if (currentExp.Substring(currentOptPos, 2) == "<>")
{
currentOptPos++;
return "<>";
}
return "<";
case ">":
if (currentExp.Substring(currentOptPos, 2) == ">=")
{
currentOptPos++;
return ">=";
}
return ">";
case "t":
if (currentExp.Substring(currentOptPos, 3) == "tan")
{
currentOptPos += 2;
return "tan";
}
return "error";
case "a":
if (currentExp.Substring(currentOptPos, 4) == "atan")
{
currentOptPos += 3;
return "atan";
}
return "error";
default:
return currentOpt;
}
}
/// <summary>
/// 转换运算符到指定的类型
/// </summary>
/// <param name="opt">运算符</param>
/// <param name="isBinaryOperator">是否为二元运算符</param>
/// <returns>返回指定的运算符类型</returns>
public static OperatorType ConvertOperator(string opt, bool isBinaryOperator)
{
switch (opt)
{
case "!": return OperatorType.NOT;
case "+": return isBinaryOperator ? OperatorType.ADD : OperatorType.PS;
case "-": return isBinaryOperator ? OperatorType.SUB : OperatorType.NS;
case "*": return isBinaryOperator ? OperatorType.MUL : OperatorType.ERR;
case "/": return isBinaryOperator ? OperatorType.DIV : OperatorType.ERR;
case "%": return isBinaryOperator ? OperatorType.MOD : OperatorType.ERR;
case "<": return isBinaryOperator ? OperatorType.LT : OperatorType.ERR;
case ">": return isBinaryOperator ? OperatorType.GT : OperatorType.ERR;
case "<=": return isBinaryOperator ? OperatorType.LE : OperatorType.ERR;
case ">=": return isBinaryOperator ? OperatorType.GE : OperatorType.ERR;
case "<>": return isBinaryOperator ? OperatorType.UT : OperatorType.ERR;
case "=": return isBinaryOperator ? OperatorType.ET : OperatorType.ERR;
case "&": return isBinaryOperator ? OperatorType.AND : OperatorType.ERR;
case "|": return isBinaryOperator ? OperatorType.OR : OperatorType.ERR;
case ",": return isBinaryOperator ? OperatorType.CA : OperatorType.ERR;
case "@": return isBinaryOperator ? OperatorType.END : OperatorType.ERR;
default: return OperatorType.ERR;
}
}
/// <summary>
/// 转换运算符到指定的类型
/// </summary>
/// <param name="opt">运算符</param>
/// <returns>返回指定的运算符类型</returns>
public static OperatorType ConvertOperator(string opt)
{
switch (opt)
{
case "!": return OperatorType.NOT;
case "+": return OperatorType.ADD;
case "-": return OperatorType.SUB;
case "*": return OperatorType.MUL;
case "/": return OperatorType.DIV;
case "%": return OperatorType.MOD;
case "<": return OperatorType.LT;
case ">": return OperatorType.GT;
case "<=": return OperatorType.LE;
case ">=": return OperatorType.GE;
case "<>": return OperatorType.UT;
case "=": return OperatorType.ET;
case "&": return OperatorType.AND;
case "|": return OperatorType.OR;
case ",": return OperatorType.CA;
case "@": return OperatorType.END;
case "tan": return OperatorType.TAN;
case "atan": return OperatorType.ATAN;
default: return OperatorType.ERR;
}
}
/// <summary>
/// 运算符是否为二元运算符,该方法有问题,暂不使用
/// </summary>
/// <param name="tokens">语法单元堆栈</param>
/// <param name="operators">运算符堆栈</param>
/// <param name="currentOpd">当前操作数</param>
/// <returns>是返回真,否返回假</returns>
public static bool IsBinaryOperator(ref Stack<object> tokens, ref Stack<Operator> operators, string currentOpd)
{
if (currentOpd != "")
{
return true;
}
else
{
object token = tokens.Peek();
if (token is Operand)
{
if (operators.Peek().Type != OperatorType.LB)
{
return true;
}
else
{
return false;
}
}
else
{
if (((Operator)token).Type == OperatorType.RB)
{
return true;
}
else
{
return false;
}
}
}
}
/// <summary>
/// 运算符优先级比较
/// </summary>
/// <param name="optA">运算符类型A</param>
/// <param name="optB">运算符类型B</param>
/// <returns>A与B相比,-1,低;0,相等;1,高</returns>
public static int ComparePriority(OperatorType optA, OperatorType optB)
{
if (optA == optB)
{
//A、B优先级相等
return 0;
}
//乘,除,余(*,/,%)
if ((optA >= OperatorType.MUL && optA <= OperatorType.MOD) &&
(optB >= OperatorType.MUL && optB <= OperatorType.MOD))
{
return 0;
}
//加,减(+,-)
if ((optA >= OperatorType.ADD && optA <= OperatorType.SUB) &&
(optB >= OperatorType.ADD && optB <= OperatorType.SUB))
{
return 0;
}
//小于,小于或等于,大于,大于或等于(<,<=,>,>=)
if ((optA >= OperatorType.LT && optA <= OperatorType.GE) &&
(optB >= OperatorType.LT && optB <= OperatorType.GE))
{
return 0;
}
//等于,不等于(=,<>)
if ((optA >= OperatorType.ET && optA <= OperatorType.UT) &&
(optB >= OperatorType.ET && optB <= OperatorType.UT))
{
return 0;
}
//三角函数
if ((optA>=OperatorType.TAN && optA<=OperatorType.ATAN)&&
(optB >= OperatorType.TAN && optB <= OperatorType.ATAN))
{
return 0;
}
if (optA < optB)
{
//A优先级高于B
return 1;
}
//A优先级低于B
return -1;
}
}
最后,我们来实现算法类RPN,此部分代码较多,因此分成几部分。
1、RPN类中的变量和属性定义
RPN类 变量和属性
1 /// <summary>
2 /// Reverse Polish Notation
3 /// 逆波兰式
4 /// </summary>
5 public class RPN
6 {
7 Stack<object> m_tokens = new Stack<object>(); //最终逆波兰式堆栈
8 /// <summary>
9 /// 最终逆波兰式堆栈
10 /// </summary>
11 public Stack<object> Tokens
12 {
13 get { return m_tokens; }
14 }
15
16 private string _RPNExpression;
17 /// <summary>
18 /// 生成的逆波兰式字符串
19 /// </summary>
20 public string RPNExpression
21 {
22 get
23 {
24 if (_RPNExpression == null)
25 {
26 foreach (var item in Tokens)
27 {
28 if (item is Operand)
29 {
30 _RPNExpression += ((Operand)item).Value + ",";
31 }
32 if (item is Operator)
33 {
34 _RPNExpression += ((Operator)item).Value + ",";
35 }
36 }
37 }
38 return _RPNExpression;
39 }
40 }
41
42 List<string> m_Operators = new List<string>(new string[]{
43 "(","tan",")","atan","!","*","/","%","+","-","<",">","=","&","|",",","@"}); //允许使用的运算符
44 }
2 /// Reverse Polish Notation
3 /// 逆波兰式
4 /// </summary>
5 public class RPN
6 {
7 Stack<object> m_tokens = new Stack<object>(); //最终逆波兰式堆栈
8 /// <summary>
9 /// 最终逆波兰式堆栈
10 /// </summary>
11 public Stack<object> Tokens
12 {
13 get { return m_tokens; }
14 }
15
16 private string _RPNExpression;
17 /// <summary>
18 /// 生成的逆波兰式字符串
19 /// </summary>
20 public string RPNExpression
21 {
22 get
23 {
24 if (_RPNExpression == null)
25 {
26 foreach (var item in Tokens)
27 {
28 if (item is Operand)
29 {
30 _RPNExpression += ((Operand)item).Value + ",";
31 }
32 if (item is Operator)
33 {
34 _RPNExpression += ((Operator)item).Value + ",";
35 }
36 }
37 }
38 return _RPNExpression;
39 }
40 }
41
42 List<string> m_Operators = new List<string>(new string[]{
43 "(","tan",")","atan","!","*","/","%","+","-","<",">","=","&","|",",","@"}); //允许使用的运算符
44 }
2、检查特殊符号是否匹配的方法
检查表达式中特殊符号(双引号、单引号、井号、左右括号)是否匹配
1 private bool IsMatching(string exp)
2 {
3 string opt = ""; //临时存储 " ' # (
4
5 for (int i = 0; i < exp.Length; i++)
6 {
7 string chr = exp.Substring(i, 1); //读取每个字符
8 if ("\"'#".Contains(chr)) //当前字符是双引号、单引号、井号的一种
9 {
10 if (opt.Contains(chr)) //之前已经读到过该字符
11 {
12 opt = opt.Remove(opt.IndexOf(chr), 1); //移除之前读到的该字符,即匹配的字符
13 }
14 else
15 {
16 opt += chr; //第一次读到该字符时,存储
17 }
18 }
19 else if ("()".Contains(chr)) //左右括号
20 {
21 if (chr == "(")
22 {
23 opt += chr;
24 }
25 else if (chr == ")")
26 {
27 if (opt.Contains("("))
28 {
29 opt = opt.Remove(opt.IndexOf("("), 1);
30 }
31 else
32 {
33 return false;
34 }
35 }
36 }
37 }
38 return (opt == "");
39 }
2 {
3 string opt = ""; //临时存储 " ' # (
4
5 for (int i = 0; i < exp.Length; i++)
6 {
7 string chr = exp.Substring(i, 1); //读取每个字符
8 if ("\"'#".Contains(chr)) //当前字符是双引号、单引号、井号的一种
9 {
10 if (opt.Contains(chr)) //之前已经读到过该字符
11 {
12 opt = opt.Remove(opt.IndexOf(chr), 1); //移除之前读到的该字符,即匹配的字符
13 }
14 else
15 {
16 opt += chr; //第一次读到该字符时,存储
17 }
18 }
19 else if ("()".Contains(chr)) //左右括号
20 {
21 if (chr == "(")
22 {
23 opt += chr;
24 }
25 else if (chr == ")")
26 {
27 if (opt.Contains("("))
28 {
29 opt = opt.Remove(opt.IndexOf("("), 1);
30 }
31 else
32 {
33 return false;
34 }
35 }
36 }
37 }
38 return (opt == "");
39 }
3、查找运算符位置
从表达式中查找运算符位置
1 /// <summary>
2 /// 从表达式中查找运算符位置
3 /// </summary>
4 /// <param name="exp">表达式</param>
5 /// <param name="findOpt">要查找的运算符</param>
6 /// <returns>返回运算符位置</returns>
7 private int FindOperator(string exp, string findOpt)
8 {
9 string opt = "";
10 for (int i = 0; i < exp.Length; i++)
11 {
12 string chr = exp.Substring(i, 1);
13 if ("\"'#".Contains(chr))//忽略双引号、单引号、井号中的运算符
14 {
15 if (opt.Contains(chr))
16 {
17 opt = opt.Remove(opt.IndexOf(chr), 1);
18 }
19 else
20 {
21 opt += chr;
22 }
23 }
24 if (opt == "")
25 {
26 if (findOpt != "")
27 {
28 if (findOpt == chr)
29 {
30 return i;
31 }
32 }
33 else
34 {
35 if (m_Operators.Exists(x => x.Contains(chr)))
36 {
37 return i;
38 }
39 }
40 }
41 }
42 return -1;
43 }
2 /// 从表达式中查找运算符位置
3 /// </summary>
4 /// <param name="exp">表达式</param>
5 /// <param name="findOpt">要查找的运算符</param>
6 /// <returns>返回运算符位置</returns>
7 private int FindOperator(string exp, string findOpt)
8 {
9 string opt = "";
10 for (int i = 0; i < exp.Length; i++)
11 {
12 string chr = exp.Substring(i, 1);
13 if ("\"'#".Contains(chr))//忽略双引号、单引号、井号中的运算符
14 {
15 if (opt.Contains(chr))
16 {
17 opt = opt.Remove(opt.IndexOf(chr), 1);
18 }
19 else
20 {
21 opt += chr;
22 }
23 }
24 if (opt == "")
25 {
26 if (findOpt != "")
27 {
28 if (findOpt == chr)
29 {
30 return i;
31 }
32 }
33 else
34 {
35 if (m_Operators.Exists(x => x.Contains(chr)))
36 {
37 return i;
38 }
39 }
40 }
41 }
42 return -1;
43 }
4、解析字符串表达式,算法的关键实现
语法解析,将中缀表达式转换成后缀表达式(即逆波兰表达式)
1 public bool Parse(string exp)
2 {
3 m_tokens.Clear();//清空语法单元堆栈
4 if (exp.Trim() == "")//表达式不能为空
5 {
6 return false;
7 }
8 else if (!this.IsMatching(exp))//括号、引号、单引号等必须配对
9 {
10 return false;
11 }
12
13 Stack<object> operands = new Stack<object>(); //操作数堆栈
14 Stack<Operator> operators = new Stack<Operator>(); //运算符堆栈
15 OperatorType optType = OperatorType.ERR; //运算符类型
16 string curOpd = ""; //当前操作数
17 string curOpt = ""; //当前运算符
18 int curPos = 0; //当前位置
19 //int funcCount = 0; //函数数量
20
21 curPos = FindOperator(exp, "");
22
23 exp += "@"; //结束操作符
24 while (true)
25 {
26 curPos = FindOperator(exp, "");
27
28 curOpd = exp.Substring(0, curPos).Trim();
29 curOpt = exp.Substring(curPos, 1);
30
31 //////////////测试代码///////////////////////////////////
32 //System.Diagnostics.Debug.WriteLine("***************");
33 //System.Diagnostics.Debug.WriteLine("当前读取的操作数:" + curOpd);
34
35 //foreach (var item in operands.ToArray())
36 //{
37 // if (item is Operand)
38 // {
39 // System.Diagnostics.Debug.WriteLine("操作数栈:" + ((Operand)item).Value);
40 // }
41 // if (item is Operator)
42 // {
43 // System.Diagnostics.Debug.WriteLine("操作数栈:" + ((Operator)item).Value);
44 // }
45 //}
46
47 //System.Diagnostics.Debug.WriteLine("当前读取的运算符:" + curOpt);
48 //foreach (var item in operators.ToArray())
49 //{
50 // System.Diagnostics.Debug.WriteLine("运算符栈:" + item.Value);
51 //}
52 ////////////////////////////////////////////////////////
53
54 //存储当前操作数到操作数堆栈
55 if (curOpd != "")
56 {
57 operands.Push(new Operand(curOpd, curOpd));
58 }
59
60 //若当前运算符为结束运算符,则停止循环
61 if (curOpt == "@")
62 {
63 break;
64 }
65 //若当前运算符为左括号,则直接存入堆栈。
66 if (curOpt == "(")
67 {
68 operators.Push(new Operator(OperatorType.LB, "("));
69 exp = exp.Substring(curPos + 1).Trim();
70 continue;
71 }
72
73 //若当前运算符为右括号,则依次弹出运算符堆栈中的运算符并存入到操作数堆栈,直到遇到左括号为止,此时抛弃该左括号.
74 if (curOpt == ")")
75 {
76 while (operators.Count > 0)
77 {
78 if (operators.Peek().Type != OperatorType.LB)
79 {
80 operands.Push(operators.Pop());
81 }
82 else
83 {
84 operators.Pop();
85 break;
86 }
87 }
88 exp = exp.Substring(curPos + 1).Trim();
89 continue;
90 }
91
92
93 //调整运算符
94 curOpt = Operator.AdjustOperator(curOpt, exp, ref curPos);
95
96 optType = Operator.ConvertOperator(curOpt);
97
98 //若运算符堆栈为空,或者若运算符堆栈栈顶为左括号,则将当前运算符直接存入运算符堆栈.
99 if (operators.Count == 0 || operators.Peek().Type == OperatorType.LB)
100 {
101 operators.Push(new Operator(optType, curOpt));
102 exp = exp.Substring(curPos + 1).Trim();
103 continue;
104 }
105
106 //若当前运算符优先级大于运算符栈顶的运算符,则将当前运算符直接存入运算符堆栈.
107 if (Operator.ComparePriority(optType, operators.Peek().Type) > 0)
108 {
109 operators.Push(new Operator(optType, curOpt));
110 }
111 else
112 {
113 //若当前运算符若比运算符堆栈栈顶的运算符优先级低或相等,则输出栈顶运算符到操作数堆栈,直至运算符栈栈顶运算符低于(不包括等于)该运算符优先级,
114 //或运算符栈栈顶运算符为左括号
115 //并将当前运算符压入运算符堆栈。
116 while (operators.Count > 0)
117 {
118 if (Operator.ComparePriority(optType, operators.Peek().Type) <= 0 && operators.Peek().Type != OperatorType.LB)
119 {
120 operands.Push(operators.Pop());
121
122 if (operators.Count == 0)
123 {
124 operators.Push(new Operator(optType, curOpt));
125 break;
126 }
127 }
128 else
129 {
130 operators.Push(new Operator(optType, curOpt));
131 break;
132 }
133 }
134
135 }
136 exp = exp.Substring(curPos + 1).Trim();
137 }
138 //转换完成,若运算符堆栈中尚有运算符时,
139 //则依序取出运算符到操作数堆栈,直到运算符堆栈为空
140 while (operators.Count > 0)
141 {
142 operands.Push(operators.Pop());
143 }
144 //调整操作数栈中对象的顺序并输出到最终栈
145 while (operands.Count > 0)
146 {
147 m_tokens.Push(operands.Pop());
148 }
149
150 return true;
151 }
2 {
3 m_tokens.Clear();//清空语法单元堆栈
4 if (exp.Trim() == "")//表达式不能为空
5 {
6 return false;
7 }
8 else if (!this.IsMatching(exp))//括号、引号、单引号等必须配对
9 {
10 return false;
11 }
12
13 Stack<object> operands = new Stack<object>(); //操作数堆栈
14 Stack<Operator> operators = new Stack<Operator>(); //运算符堆栈
15 OperatorType optType = OperatorType.ERR; //运算符类型
16 string curOpd = ""; //当前操作数
17 string curOpt = ""; //当前运算符
18 int curPos = 0; //当前位置
19 //int funcCount = 0; //函数数量
20
21 curPos = FindOperator(exp, "");
22
23 exp += "@"; //结束操作符
24 while (true)
25 {
26 curPos = FindOperator(exp, "");
27
28 curOpd = exp.Substring(0, curPos).Trim();
29 curOpt = exp.Substring(curPos, 1);
30
31 //////////////测试代码///////////////////////////////////
32 //System.Diagnostics.Debug.WriteLine("***************");
33 //System.Diagnostics.Debug.WriteLine("当前读取的操作数:" + curOpd);
34
35 //foreach (var item in operands.ToArray())
36 //{
37 // if (item is Operand)
38 // {
39 // System.Diagnostics.Debug.WriteLine("操作数栈:" + ((Operand)item).Value);
40 // }
41 // if (item is Operator)
42 // {
43 // System.Diagnostics.Debug.WriteLine("操作数栈:" + ((Operator)item).Value);
44 // }
45 //}
46
47 //System.Diagnostics.Debug.WriteLine("当前读取的运算符:" + curOpt);
48 //foreach (var item in operators.ToArray())
49 //{
50 // System.Diagnostics.Debug.WriteLine("运算符栈:" + item.Value);
51 //}
52 ////////////////////////////////////////////////////////
53
54 //存储当前操作数到操作数堆栈
55 if (curOpd != "")
56 {
57 operands.Push(new Operand(curOpd, curOpd));
58 }
59
60 //若当前运算符为结束运算符,则停止循环
61 if (curOpt == "@")
62 {
63 break;
64 }
65 //若当前运算符为左括号,则直接存入堆栈。
66 if (curOpt == "(")
67 {
68 operators.Push(new Operator(OperatorType.LB, "("));
69 exp = exp.Substring(curPos + 1).Trim();
70 continue;
71 }
72
73 //若当前运算符为右括号,则依次弹出运算符堆栈中的运算符并存入到操作数堆栈,直到遇到左括号为止,此时抛弃该左括号.
74 if (curOpt == ")")
75 {
76 while (operators.Count > 0)
77 {
78 if (operators.Peek().Type != OperatorType.LB)
79 {
80 operands.Push(operators.Pop());
81 }
82 else
83 {
84 operators.Pop();
85 break;
86 }
87 }
88 exp = exp.Substring(curPos + 1).Trim();
89 continue;
90 }
91
92
93 //调整运算符
94 curOpt = Operator.AdjustOperator(curOpt, exp, ref curPos);
95
96 optType = Operator.ConvertOperator(curOpt);
97
98 //若运算符堆栈为空,或者若运算符堆栈栈顶为左括号,则将当前运算符直接存入运算符堆栈.
99 if (operators.Count == 0 || operators.Peek().Type == OperatorType.LB)
100 {
101 operators.Push(new Operator(optType, curOpt));
102 exp = exp.Substring(curPos + 1).Trim();
103 continue;
104 }
105
106 //若当前运算符优先级大于运算符栈顶的运算符,则将当前运算符直接存入运算符堆栈.
107 if (Operator.ComparePriority(optType, operators.Peek().Type) > 0)
108 {
109 operators.Push(new Operator(optType, curOpt));
110 }
111 else
112 {
113 //若当前运算符若比运算符堆栈栈顶的运算符优先级低或相等,则输出栈顶运算符到操作数堆栈,直至运算符栈栈顶运算符低于(不包括等于)该运算符优先级,
114 //或运算符栈栈顶运算符为左括号
115 //并将当前运算符压入运算符堆栈。
116 while (operators.Count > 0)
117 {
118 if (Operator.ComparePriority(optType, operators.Peek().Type) <= 0 && operators.Peek().Type != OperatorType.LB)
119 {
120 operands.Push(operators.Pop());
121
122 if (operators.Count == 0)
123 {
124 operators.Push(new Operator(optType, curOpt));
125 break;
126 }
127 }
128 else
129 {
130 operators.Push(new Operator(optType, curOpt));
131 break;
132 }
133 }
134
135 }
136 exp = exp.Substring(curPos + 1).Trim();
137 }
138 //转换完成,若运算符堆栈中尚有运算符时,
139 //则依序取出运算符到操作数堆栈,直到运算符堆栈为空
140 while (operators.Count > 0)
141 {
142 operands.Push(operators.Pop());
143 }
144 //调整操作数栈中对象的顺序并输出到最终栈
145 while (operands.Count > 0)
146 {
147 m_tokens.Push(operands.Pop());
148 }
149
150 return true;
151 }
5、计算
对逆波兰表达式求值
1 public object Evaluate()
2 {
3 /*
4 逆波兰表达式求值算法:
5 1、循环扫描语法单元的项目。
6 2、如果扫描的项目是操作数,则将其压入操作数堆栈,并扫描下一个项目。
7 3、如果扫描的项目是一个二元运算符,则对栈的顶上两个操作数执行该运算。
8 4、如果扫描的项目是一个一元运算符,则对栈的最顶上操作数执行该运算。
9 5、将运算结果重新压入堆栈。
10 6、重复步骤2-5,堆栈中即为结果值。
11 */
12
13 if (m_tokens.Count == 0) return null;
14
15 object value = null;
16 Stack<Operand> opds = new Stack<Operand>();
17 Stack<object> pars = new Stack<object>();
18 Operand opdA, opdB;
19
20 foreach (object item in m_tokens)
21 {
22 if (item is Operand)
23 {
24 //TODO 解析公式,替换参数
25
26 //如果为操作数则压入操作数堆栈
27 opds.Push((Operand)item);
28 }
29 else
30 {
31 switch (((Operator)item).Type)
32 {
33 #region 乘,*,multiplication
34 case OperatorType.MUL:
35 opdA = opds.Pop();
36 opdB = opds.Pop();
37 if (Operand.IsNumber(opdA.Value) && Operand.IsNumber(opdB.Value))
38 {
39 opds.Push(new Operand(OperandType.NUMBER, double.Parse(opdB.Value.ToString()) * double.Parse(opdA.Value.ToString())));
40 }
41 else
42 {
43 throw new Exception("乘运算的两个操作数必须均为数字");
44 }
45 break;
46 #endregion
47
48 #region 除,/,division
49 case OperatorType.DIV:
50 opdA = opds.Pop();
51 opdB = opds.Pop();
52 if (Operand.IsNumber(opdA.Value) && Operand.IsNumber(opdB.Value))
53 {
54 opds.Push(new Operand(OperandType.NUMBER, double.Parse(opdB.Value.ToString()) / double.Parse(opdA.Value.ToString())));
55 }
56 else
57 {
58 throw new Exception("除运算的两个操作数必须均为数字");
59 }
60 break;
61 #endregion
62
63 #region 余,%,modulus
64 case OperatorType.MOD:
65 opdA = opds.Pop();
66 opdB = opds.Pop();
67 if (Operand.IsNumber(opdA.Value) && Operand.IsNumber(opdB.Value))
68 {
69 opds.Push(new Operand(OperandType.NUMBER, double.Parse(opdB.Value.ToString()) % double.Parse(opdA.Value.ToString())));
70 }
71 else
72 {
73 throw new Exception("余运算的两个操作数必须均为数字");
74 }
75 break;
76 #endregion
77
78 #region 加,+,Addition
79 case OperatorType.ADD:
80 opdA = opds.Pop();
81 opdB = opds.Pop();
82 if (Operand.IsNumber(opdA.Value) && Operand.IsNumber(opdB.Value))
83 {
84 opds.Push(new Operand(OperandType.NUMBER, double.Parse(opdB.Value.ToString()) + double.Parse(opdA.Value.ToString())));
85 }
86 else
87 {
88 throw new Exception("加运算的两个操作数必须均为数字");
89 }
90 break;
91 #endregion
92
93 #region 减,-,subtraction
94 case OperatorType.SUB:
95 opdA = opds.Pop();
96 opdB = opds.Pop();
97 if (Operand.IsNumber(opdA.Value) && Operand.IsNumber(opdB.Value))
98 {
99 opds.Push(new Operand(OperandType.NUMBER, double.Parse(opdB.Value.ToString()) - double.Parse(opdA.Value.ToString())));
100 }
101 else
102 {
103 throw new Exception("减运算的两个操作数必须均为数字");
104 }
105 break;
106 #endregion
107
108 #region 正切,tan,subtraction
109 case OperatorType.TAN:
110 opdA = opds.Pop();
111 if (Operand.IsNumber(opdA.Value))
112 {
113 opds.Push(new Operand(OperandType.NUMBER, Math.Tan(double.Parse(opdA.Value.ToString())*Math.PI/180)));
114 }
115 else
116 {
117 throw new Exception("正切运算的1个操作数必须均为角度数字");
118 }
119 break;
120 #endregion
121
122 #region 反正切,atan,subtraction
123 case OperatorType.ATAN:
124 opdA = opds.Pop();
125 if (Operand.IsNumber(opdA.Value))
126 {
127 opds.Push(new Operand(OperandType.NUMBER, Math.Atan(double.Parse(opdA.Value.ToString()))));
128 }
129 else
130 {
131 throw new Exception("反正切运算的1个操作数必须均为数字");
132 }
133 break;
134 #endregion
135
136 }
137 }
138 }
139
140 if (opds.Count == 1)
141 {
142 value = opds.Pop().Value;
143 }
144
145 return value;
146 }
2 {
3 /*
4 逆波兰表达式求值算法:
5 1、循环扫描语法单元的项目。
6 2、如果扫描的项目是操作数,则将其压入操作数堆栈,并扫描下一个项目。
7 3、如果扫描的项目是一个二元运算符,则对栈的顶上两个操作数执行该运算。
8 4、如果扫描的项目是一个一元运算符,则对栈的最顶上操作数执行该运算。
9 5、将运算结果重新压入堆栈。
10 6、重复步骤2-5,堆栈中即为结果值。
11 */
12
13 if (m_tokens.Count == 0) return null;
14
15 object value = null;
16 Stack<Operand> opds = new Stack<Operand>();
17 Stack<object> pars = new Stack<object>();
18 Operand opdA, opdB;
19
20 foreach (object item in m_tokens)
21 {
22 if (item is Operand)
23 {
24 //TODO 解析公式,替换参数
25
26 //如果为操作数则压入操作数堆栈
27 opds.Push((Operand)item);
28 }
29 else
30 {
31 switch (((Operator)item).Type)
32 {
33 #region 乘,*,multiplication
34 case OperatorType.MUL:
35 opdA = opds.Pop();
36 opdB = opds.Pop();
37 if (Operand.IsNumber(opdA.Value) && Operand.IsNumber(opdB.Value))
38 {
39 opds.Push(new Operand(OperandType.NUMBER, double.Parse(opdB.Value.ToString()) * double.Parse(opdA.Value.ToString())));
40 }
41 else
42 {
43 throw new Exception("乘运算的两个操作数必须均为数字");
44 }
45 break;
46 #endregion
47
48 #region 除,/,division
49 case OperatorType.DIV:
50 opdA = opds.Pop();
51 opdB = opds.Pop();
52 if (Operand.IsNumber(opdA.Value) && Operand.IsNumber(opdB.Value))
53 {
54 opds.Push(new Operand(OperandType.NUMBER, double.Parse(opdB.Value.ToString()) / double.Parse(opdA.Value.ToString())));
55 }
56 else
57 {
58 throw new Exception("除运算的两个操作数必须均为数字");
59 }
60 break;
61 #endregion
62
63 #region 余,%,modulus
64 case OperatorType.MOD:
65 opdA = opds.Pop();
66 opdB = opds.Pop();
67 if (Operand.IsNumber(opdA.Value) && Operand.IsNumber(opdB.Value))
68 {
69 opds.Push(new Operand(OperandType.NUMBER, double.Parse(opdB.Value.ToString()) % double.Parse(opdA.Value.ToString())));
70 }
71 else
72 {
73 throw new Exception("余运算的两个操作数必须均为数字");
74 }
75 break;
76 #endregion
77
78 #region 加,+,Addition
79 case OperatorType.ADD:
80 opdA = opds.Pop();
81 opdB = opds.Pop();
82 if (Operand.IsNumber(opdA.Value) && Operand.IsNumber(opdB.Value))
83 {
84 opds.Push(new Operand(OperandType.NUMBER, double.Parse(opdB.Value.ToString()) + double.Parse(opdA.Value.ToString())));
85 }
86 else
87 {
88 throw new Exception("加运算的两个操作数必须均为数字");
89 }
90 break;
91 #endregion
92
93 #region 减,-,subtraction
94 case OperatorType.SUB:
95 opdA = opds.Pop();
96 opdB = opds.Pop();
97 if (Operand.IsNumber(opdA.Value) && Operand.IsNumber(opdB.Value))
98 {
99 opds.Push(new Operand(OperandType.NUMBER, double.Parse(opdB.Value.ToString()) - double.Parse(opdA.Value.ToString())));
100 }
101 else
102 {
103 throw new Exception("减运算的两个操作数必须均为数字");
104 }
105 break;
106 #endregion
107
108 #region 正切,tan,subtraction
109 case OperatorType.TAN:
110 opdA = opds.Pop();
111 if (Operand.IsNumber(opdA.Value))
112 {
113 opds.Push(new Operand(OperandType.NUMBER, Math.Tan(double.Parse(opdA.Value.ToString())*Math.PI/180)));
114 }
115 else
116 {
117 throw new Exception("正切运算的1个操作数必须均为角度数字");
118 }
119 break;
120 #endregion
121
122 #region 反正切,atan,subtraction
123 case OperatorType.ATAN:
124 opdA = opds.Pop();
125 if (Operand.IsNumber(opdA.Value))
126 {
127 opds.Push(new Operand(OperandType.NUMBER, Math.Atan(double.Parse(opdA.Value.ToString()))));
128 }
129 else
130 {
131 throw new Exception("反正切运算的1个操作数必须均为数字");
132 }
133 break;
134 #endregion
135
136 }
137 }
138 }
139
140 if (opds.Count == 1)
141 {
142 value = opds.Pop().Value;
143 }
144
145 return value;
146 }
至此,算法实现已经完毕,下面我们来看下,如何使用RPN类来计算表达式。
1 private void Test()
2 {
3 string tmpExp="1.0+3/2-tan(45)/(1+1)";
4 RPN rpn = new RPN();
5 if (rpn.Parse(tmpExp))
6 {
7 Console.WriteLine(rpn.Evaluate());
8 }
9 }
2 {
3 string tmpExp="1.0+3/2-tan(45)/(1+1)";
4 RPN rpn = new RPN();
5 if (rpn.Parse(tmpExp))
6 {
7 Console.WriteLine(rpn.Evaluate());
8 }
9 }