表达式计算器的实现

一、前言

    关于表达式计算器的实现,在这里分享一下我的思路,也希望大家提出一些改进建议。

 

二、实现表达式计算的主要思路。

    1、使用的数据结构。

     以前的版本实现表达式计算用的是二叉树数据结构,二叉树有两个子节点,最多支持双目运算符或者带两个参数的函数,可是如果函数的参数很多,就不好处理了,所以当前的版本,用的数据结构是动态数组,实现原理就是先把字符串表达式转换成动态数组,数组中存储运算符、参与运算的数、括号等。这样运算符或者函数的参数个数就不受限制,可以支持更多类型的运算符。

 

    2、对运算符进行分类。

    对运算符的分类处理是该程序的一个重要思路,运算符虽然有很多,但是可以将运算符归类,针对每一类运算符分别处理,这样核心算法就不会涉及到具体的运算符,只会涉及到运算符的类别。这样以后如果要扩展更多的运算符就会很方便,不需要再修改核心算法的代码,只需要修改运算符集合类就可以了。

     用一个枚举类表示运算符的种类,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/// <summary>
/// 运算符类型
/// </summary>
enum OpeType
{
    /// <summary>
    /// 该运算因子不是运算符
    /// </summary>
    notOperator,
    /// <summary>
    /// 常数或变量(没有参数的运算符)
    /// </summary>
    noParameter,
    /// <summary>
    /// '+'或'-'
    /// 这两个运算符即可以当正负号使用又可以当加减运算符使用
    /// </summary>
    PlusOrMinus,
    /// <summary>
    /// 参数全在左边的运算符
    /// </summary>
    left,
    /// <summary>
    /// 参数全在右边的运算符
    /// </summary>
    right,
    /// <summary>
    /// 左边和右边都有参数的运算符
    /// </summary>
    bothSides,
    /// <summary>
    /// 左括号
    /// </summary>
    leftParenthesis,
    /// <summary>
    /// 右括号
    /// </summary>
    rightParenthesis,
    /// <summary>
    /// 分隔符,这里指逗号
    /// </summary>
    Separator
}

  

    3、对表达式的进行合法性检查的思路。

    对表达式的合法性检查,我没有学过编译原理,不懂什么是文法分析、词法分析。这个程序检查表达式的合法性的原理是:针对每一类运算符,分别进行判断,检查其参数的个数,参数是在右边还是在左边等等,主要代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
#region 第四次处理
//第四次处理,判断表达式是否合法,并在合适的地方插入乘号
for (int i = 0; i < valList.Count - 1; i++)
{
    #region 当前运算因子是数字
    if (valList[i].type == ValType.Number)//数字
    {
        if (valList[i + 1].type == ValType.Operator)//右边是运算符
        {
            switch (valList[i + 1].OpeType)
            {
                case OpeType.bothSides://正确
                    break;
                case OpeType.left://正确
                    break;
                case OpeType.leftParenthesis:
                    Insert(opeList.GetOpe("*"), i + 1);
                    break;
                case OpeType.noParameter:
                    Insert(opeList.GetOpe("*"), i + 1);
                    break;
                case OpeType.PlusOrMinus://正确
                    break;
                case OpeType.right:
                    Insert(opeList.GetOpe("*"), i + 1);
                    break;
                case OpeType.rightParenthesis://正确
                    break;
                case OpeType.Separator://正确
                    break;
            }
        }
        else//右边是数字
        {
            Insert(opeList.GetOpe("*"), i + 1);
        }
    }
    #endregion
 
    #region 当前运算因子是运算符
    if (valList[i].type == ValType.Operator)//运算符
    {
        #region 当前运算符右边是运算符
        if (valList[i + 1].type == ValType.Operator)//右边是运算符
        {
            switch (valList[i].OpeType)//左运算符
            {
                #region case OpeType.bothSides://左运算符参数信息
                case OpeType.bothSides://左运算符参数信息
                    switch (valList[i + 1].OpeType)//右运算符
                    {
                        case OpeType.bothSides:
                            MakeException(i);
                            break;
                        case OpeType.left:
                            MakeException(i);
                            break;
                        case OpeType.leftParenthesis://正确
                            break;
                        case OpeType.noParameter://正确
                            break;
                        case OpeType.PlusOrMinus:
                            MakeException(i);
                            break;
                        case OpeType.right://正确
                            break;
                        case OpeType.rightParenthesis:
                            MakeException(i);
                            break;
                        case OpeType.Separator:
                            MakeException(i);
                            break;
                    }
                    break;
                #endregion
 
                #region case OpeType.left://左运算符参数信息
                case OpeType.left://左运算符参数信息
                    switch (valList[i + 1].OpeType)//右运算符
                    {
                        case OpeType.bothSides://正确
                            break;
                        case OpeType.left://正确
                            break;
                        case OpeType.leftParenthesis:
                            Insert(opeList.GetOpe("*"), i + 1);
                            break;
                        case OpeType.noParameter:
                            Insert(opeList.GetOpe("*"), i + 1);
                            break;
                        case OpeType.PlusOrMinus://正确
                            break;
                        case OpeType.right:
                            Insert(opeList.GetOpe("*"), i + 1);
                            break;
                        case OpeType.rightParenthesis://正确
                            break;
                        case OpeType.Separator: //正确
                            break;
                    }
                    break;
                #endregion
 
                #region case OpeType.leftParenthesis://左运算符参数信息
                case OpeType.leftParenthesis://左运算符参数信息
                    switch (valList[i + 1].OpeType)//右运算符
                    {
                        case OpeType.bothSides:
                            int pos = i + 1 >= 0 ? i + 1 : i;
                            MakeException(pos);
                            break;
                        case OpeType.left:
                            pos = i + 1 >= 0 ? i + 1 : i;
                            MakeException(pos);
                            break;
                        case OpeType.leftParenthesis://正确
                            break;
                        case OpeType.noParameter://正确
                            break;
                        case OpeType.PlusOrMinus://正确
                            break;
                        case OpeType.right://正确
                            break;
                        case OpeType.rightParenthesis:
                            pos = i - 1 >= 0 ? i - 1 : i;
                            MakeException(pos);
                            break;
                        case OpeType.Separator:
                            pos = i - 1 >= 0 ? i - 1 : i;
                            MakeException(pos);
                            break;
                    }
                    break;
                #endregion
 
                #region case OpeType.noParameter://左运算符参数信息
                case OpeType.noParameter://左运算符参数信息
                    switch (valList[i + 1].OpeType)//右运算符
                    {
                        case OpeType.bothSides://正确
                            break;
                        case OpeType.left://正确
                            break;
                        case OpeType.leftParenthesis:
                            Insert(opeList.GetOpe("*"), i + 1);
                            break;
                        case OpeType.noParameter:
                            Insert(opeList.GetOpe("*"), i + 1);
                            break;
                        case OpeType.PlusOrMinus://正确
                            break;
                        case OpeType.right:
                            Insert(opeList.GetOpe("*"), i + 1);
                            break;
                        case OpeType.rightParenthesis://正确
                            break;
                        case OpeType.Separator: //正确
                            break;
                    }
                    break;
                #endregion
 
                #region case OpeType.PlusOrMinus://左运算符参数信息
                case OpeType.PlusOrMinus://左运算符参数信息
                    switch (valList[i + 1].OpeType)//右运算符
                    {
                        case OpeType.bothSides:
                            MakeException(i);
                            break;
                        case OpeType.left:
                            MakeException(i);
                            break;
                        case OpeType.leftParenthesis://正确
                            break;
                        case OpeType.noParameter://正确
                            break;
                        case OpeType.PlusOrMinus:
                            MakeException(i);
                            break;
                        case OpeType.right://正确
                            break;
                        case OpeType.rightParenthesis:
                            MakeException(i);
                            break;
                        case OpeType.Separator:
                            MakeException(i);
                            break;
                    }
                    break;
                #endregion
 
                #region case OpeType.right://左运算符参数信息
                case OpeType.right://左运算符参数信息
                    switch (valList[i + 1].OpeType)//右运算符
                    {
                        case OpeType.bothSides:
                            MakeException(i);
                            break;
                        case OpeType.left:
                            MakeException(i);
                            break;
                        case OpeType.leftParenthesis://正确
                            break;
                        case OpeType.noParameter:
                            MakeException(i);
                            break;
                        case OpeType.PlusOrMinus:
                            MakeException(i);
                            break;
                        case OpeType.right:
                            MakeException(i);
                            break;
                        case OpeType.rightParenthesis:
                            MakeException(i);
                            break;
                        case OpeType.Separator:
                            MakeException(i);
                            break;
                    }
                    break;
                #endregion
 
                #region case OpeType.rightParenthesis://左运算符参数信息
                case OpeType.rightParenthesis://左运算符参数信息
                    switch (valList[i + 1].OpeType)//右运算符
                    {
                        case OpeType.bothSides://正确
                            break;
                        case OpeType.left://正确
                            break;
                        case OpeType.leftParenthesis:
                            Insert(opeList.GetOpe("*"), i + 1);
                            break;
                        case OpeType.noParameter:
                            Insert(opeList.GetOpe("*"), i + 1);
                            break;
                        case OpeType.PlusOrMinus://正确
                            break;
                        case OpeType.right:
                            Insert(opeList.GetOpe("*"), i + 1);
                            break;
                        case OpeType.rightParenthesis://正确
                            break;
                        case OpeType.Separator://正确
                            break;
                    }
                    break;
                #endregion
 
                #region case OpeType.Separator://左运算符参数信息
                case OpeType.Separator://左运算符参数信息
                    switch (valList[i + 1].OpeType)//右运算符
                    {
                        case OpeType.bothSides:
                            MakeException(i + 1);
                            break;
                        case OpeType.left:
                            MakeException(i + 1);
                            break;
                        case OpeType.leftParenthesis://正确
                            break;
                        case OpeType.noParameter://正确
                            break;
                        case OpeType.PlusOrMinus://正确
                            break;
                        case OpeType.right://正确
                            break;
                        case OpeType.rightParenthesis:
                            MakeException(i);
                            break;
                        case OpeType.Separator:
                            MakeException(i);
                            break;
                    }
                    break;
                #endregion
 
            }
        }
        #endregion
 
        #region 当前运算符右边是数字
        else if (valList[i + 1].type == ValType.Number)//运算符右边是数字
        {
            switch (valList[i].OpeType)
            {
                case OpeType.bothSides://正确
                    break;
                case OpeType.left:
                    Insert(opeList.GetOpe("*"), i + 1);
                    break;
                case OpeType.leftParenthesis://正确
                    break;
                case OpeType.noParameter:
                    Insert(opeList.GetOpe("*"), i + 1);
                    break;
                case OpeType.PlusOrMinus://正确
                    break;
                case OpeType.right:
                    MakeException(i);
                    break;
                case OpeType.rightParenthesis:
                    Insert(opeList.GetOpe("*"), i + 1);
                    break;
                case OpeType.Separator: //正确
                    break;
            }
        }
        #endregion
 
    }
    #endregion
 
}
#endregion

三、下面是表达式计算过程的主要步骤:

1、将字符串表达式中的数字、运算符、括号、逗号等提取出来,按顺序存储在一个动态数组中。

    原理很简单,就是通过字符串搜索来实现,扫描字符串表达式,依次把运算符取出来放到动态数组中,运算符之间的内容就是参与运算的数了。

    把字符串表达式转换成运算符、括号、逗号和数字的动态数组后,后面将处理这个数组,完成运算。

    部分代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#region 将字符串表达式转换成运算因子(数字、常数及运算符)列表
/// <summary>
/// 将字符串表达式转换成运算因子列表
/// </summary>
/// <param name="str">字符串表达式</param>
private void ToList(List<CalVal> valList, string str)
{
    do
    {
        //字符串中首个运算符的位置
        int opePos = GetOpePos(str);
 
        CalNum num = null;
        CalOpe ope = null;
 
        if (opePos > 0)//找到运算符且它前面有数字
        {
            num = GetNum(ref str, opePos);
        }
        else if (opePos == 0)//找到运算符且它在字符串最前面
        {
            ope = GetOpe(ref str);
        }
        else//没有找到运算符
        {
            num = GetNum(ref str);
        }
 
        if (num != null)
        {
            valList.Add(new CalVal(num));
        }
 
        if (ope != null)
        {
            valList.Add(new CalVal(ope));
        }
    } while (str != "");
}
#endregion
 
#region 获取字符串中首个运算符或常数的位置
/// <summary>
/// 获取字符串中首个运算符或常数的位置
/// </summary>
/// <param name="str">字符串</param>
/// <returns>值若为-1表示未找到</returns>
private int GetOpePos(string str)
{
    CalOpeList opeList = new CalOpeList();
 
    int pos = -1;
    for (int i = 0; i < opeList.count; i++)
    {
        int k = -1;
 
        int opeIndex = str.IndexOf(opeList.opeList[i].tag);
 
        //科学计数法的情况:如果'+'或'-'的前面是'E'
        if (opeList.opeList[i].opeType == OpeType.PlusOrMinus
            && opeIndex - 1 >= 0
            && str.Substring(opeIndex - 1, 1) == "E")
        {
            //从'+'或'-'的后面重新查找
            k = str.Substring(opeIndex + 1).IndexOf(opeList.opeList[i].tag);
 
            if (k != -1)//如果找到
            {
                //计算该运算符的位置
                k += opeIndex + 1;
            }
        }
        else
        {
            k = opeIndex;
        }
 
        if (pos == -1)
        {
            pos = k;
        }
        else if (k >= 0 && k < pos)
        {
            pos = k;
        }
    }
 
    return pos;//值若为-1表示未找到
}
#endregion
 
#region 获得运算符
/// <summary>
/// 获得运算符
/// </summary>
private CalOpe GetOpe(ref string str)
{
    CalOpeList opeList = new CalOpeList();
    CalOpe ope = null;
 
    for (int i = 0; i < opeList.count; i++)
    {
        if (str.IndexOf(opeList.opeList[i].tag) == 0)
        {
            ope = opeList.opeList[i];
            //更新str
            str = str.Substring(opeList.opeList[i].tag.Length);
            break;
        }
    }
 
    return ope;
}
#endregion
 
#region 获取数字
/// <summary>
/// 获取数字
/// </summary>
private CalNum GetNum(ref string str, int opePos)
{
    CalNum result = null;
 
    result = new CalNum(str.Substring(0, opePos));
 
    //更新str
    str = str.Substring(opePos);
 
    return result;
}
 
/// <summary>
/// 获取数字
/// </summary>
private CalNum GetNum(ref string str)
{
    CalNum result = null;
 
    result = new CalNum(str);
 
    //更新str
    str = "";
 
    return result;
}
#endregion

2、优先级的处理。

    优先级的处理是表达式计算过程中的一个关键问题。
    动态数组中的每个元素(运算符、分隔符或数字等)都有一个优先级,对存储表达式的动态数组从前往后扫描,遇到左括号,将运算符的优先级提升,遇到右括号的话,将运算符的优先级降低。这样处理过后,动态数组中的运算符的优先级各不相同,括号中的运算符的优先级就会高于括号外的运算符的优先级。比如括号外的加号的优先级低于括号内的加号的优先级,因为在处理的过程中把括号内的加号的优先级提升了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/// <summary>
 /// 优先级处理,提高括号中的算式的运算符的优先级
 /// </summary>
 private void LevelProcess()
 {
     int delLevel = 0;//优先级增量
 
     for (int i = 0; i < valList.Count; i++)
     {
         if (valList[i].type == ValType.Operator)
         {
             //如果是左括号
             if (valList[i].OpeType == OpeType.leftParenthesis)
             {
                 delLevel += 1000;
                 continue;
             }
 
             //如果是右括号
             if (valList[i].OpeType == OpeType.rightParenthesis)
             {
                 delLevel -= 1000;
                 continue;
             }
 
             valList[i].level = valList[i].ope.level + delLevel;
         }
     }
 }

3、在计算存储在动态数组中的表达式前,先生成优先级列表,并按优先级从高到低排好序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
        #region 生成优先级列表
        /// <summary>
        /// 生成优先级列表
        /// </summary>
        private void MakeLevelList()
        {
            #region 生成优先级列表,优先级按从高到低存储
            //逐个扫描运算因子,提取优先级列表,并按优先级从高到低存储
            for (int i = 0; i < valList.Count; i++)
            {
                //如果是运算符
                if (valList[i].type == ValType.Operator)
                {
                    //如果是括号或分隔符
                    if (valList[i].OpeType == OpeType.leftParenthesis
                        || valList[i].OpeType == OpeType.rightParenthesis
                        || valList[i].OpeType == OpeType.Separator)
                    {
                        continue;
                    }
                    InsertIntoLevelList(ref levelList, valList[i].level);
                }
            }
            #endregion
        }
        #endregion
 
#region 将优先级插入到优先级列表中
        /// <summary>
        /// 将优先级插入到优先级列表中
        /// </summary>
        /// <param name="levelList">优先级列表</param>
        /// <param name="level">要插入的优先级</param>
        private void InsertIntoLevelList(ref List<int> levelList, int level)
        {
            //列表为空的情况
            if (levelList.Count == 0)
            {
                levelList.Add(level);
                return;
            }
 
            //该优先级是否已存在
            for (int i = 0; i < levelList.Count; i++)
            {
                //该优先级已存在
                if (level == levelList[i])
                {
                    return;
                }
            }
 
            int k = 0;
            for (; k < levelList.Count; k++)
            {
                if (level > levelList[k])
                {
                    levelList.Insert(k, level);
                    break;
                }
            }
            if (k >= levelList.Count)
            {
                levelList.Add(level);
            }
        }
        #endregion

4、遍历优先级列表,按照优先级从高到低,扫描表达式动态数组,先计算优先级高的运算,用计算结果替换掉计算之前的运算符和参与运算的数。当把优先级列表中的优先级都处理完,对表达式的计算也就结束了,这时,表达式动态数组中将只剩下计算结果。

    下面是计算过程的主要代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
#region 核心算法,对于当前优先级,扫描运算因子列表并计算
if (levelList.Count != 0)//优先级列表不为空
{
    #region 处理当前优先级
    //对于当前优先级,逐个扫描运算因子,处理具有该优先级的运算
    for (int i = 0; i < valList.Count; i++)
    {
        //找到具有该优先级的运算符
        if (valList[i].type == ValType.Operator
            && valList[i].level == levelList[0])//该运算因子的优先级等于当前优先级
        {
            bool isSign = false;//Sign为true表示当前运算因子是正负号
            currentPos = valList[i].primalPos;//记录当前运算因子在列表中的原始位置
 
            //参数列表
            List<CalNum> numList = new List<CalNum>();
            //临时计算结果
            CalNum num;
 
            switch (valList[i].OpeType)//i表示该运算因子的位置
            {
                #region case OpeType.PlusOrMinus:
                case OpeType.PlusOrMinus:
                    //若该运算符前面没有运算因子
                    //或前一个运算因子是运算符,则按正负号计算
                    if (i == 0 || (i - 1 >= 0 && valList[i - 1].type == ValType.Operator))
                    {
                        isSign = true;//是正负号
                        //获取该运算符的参数
                        if (i + 1 < valList.Count && valList[i + 1].type == ValType.Number)
                        {
                            //注意,下面第一句不可省略
                            numList = new List<CalNum>();
 
                            numList.Add(valList[i + 1].num);
                        }
 
                        //计算
                        num = CalOpeList.Calculate(valList[i].ope, numList);
                        //更新运算因子列表
                        ReplaceVal(num, 2, i);
 
                        //i无需调整
                    }
                    else//若前一个运算因子是操作数,则按加减号计算
                    {
                        //获取该运算符的参数
                        if (valList[i - 1].type == ValType.Number
                            && i + 1 < valList.Count && valList[i + 1].type == ValType.Number)
                        {
                            //注意,下面第一句不可省略
                            numList = new List<CalNum>();
 
                            numList.Add(valList[i - 1].num);
                            numList.Add(valList[i + 1].num);
                        }
 
                        //计算
                        num = CalOpeList.Calculate(valList[i].ope, numList);
                        //更新运算因子列表
                        ReplaceVal(num, 3, i - 1);
                        //调整i
                        i--;
                    }
                    break;
                #endregion
 
                #region case OpeType.bothSides:
                case OpeType.bothSides:
                    //获取该运算符的参数
                    if (i >= 1 && valList[i - 1].type == ValType.Number
                        && i + 1 < valList.Count && valList[i + 1].type == ValType.Number)
                    {
                        //注意,下面第一句不可省略
                        numList = new List<CalNum>();
 
                        numList.Add(valList[i - 1].num);
                        numList.Add(valList[i + 1].num);
                    }
 
                    //计算
                    num = CalOpeList.Calculate(valList[i].ope, numList);
                    //更新运算因子列表
                    ReplaceVal(num, 3, i - 1);
                    //调整i
                    i--;
                    break;
                #endregion
 
                #region case OpeType.left:
                case OpeType.left:
                    //获取该运算符的参数
                    if (i >= 1 && valList[i - 1].type == ValType.Number)
                    {
                        //注意,下面第一句不可省略
                        numList = new List<CalNum>();
 
                        numList.Add(valList[i - 1].num);
                    }
 
                    //计算
                    num = CalOpeList.Calculate(valList[i].ope, numList);
                    //更新运算因子列表
                    ReplaceVal(num, 2, i - 1);
                    //调整i
                    i--;
                    break;
                #endregion
 
                #region case OpeType.noParameter:
                case OpeType.noParameter:
                    //注意,下面第一句不可省略
                    numList = new List<CalNum>();
 
                    //计算
                    num = CalOpeList.Calculate(valList[i].ope, numList);
                    //更新运算因子列表
                    ReplaceVal(num, 1, i);
                    break;
                #endregion
 
                #region case OpeType.right:
                case OpeType.right:
                    #region 该运算符只有一个参数,且它的右边是常数
                    if (i + 1 < valList.Count
                        && valList[i].ParameterNumber == 1
                        && valList[i + 1].type == ValType.Number)
                    {
                        //获取该运算符的参数
                        //注意,下面第一句不可省略
                        numList = new List<CalNum>();
                        numList.Add(valList[i + 1].num);
 
                        //计算
                        num = CalOpeList.Calculate(valList[i].ope, numList);
                        //更新运算因子列表
                        ReplaceVal(num, 2, i);
                    }
                    #endregion
 
                    #region 该运算符不是只有一个参数,或者它的右边不是常数
                    else
                    {
                        //计算参数个数
                        int count = 0;
 
                        int k = i + 1;
                        //从运算符后面开始检测
                        //如果是左括号、分隔符或数字,则执行while中语句
                        while (k < valList.Count
                            && (valList[k].type == ValType.Number
                            || valList[k].OpeType == OpeType.Separator
                            || valList[k].OpeType == OpeType.leftParenthesis))
                        {
                            //如果是数字,参数个数加1
                            if (valList[k].type == ValType.Number)
                            {
                                count++;
                            }
                            k++;
                        }
 
                        //注意,下面第一句不可省略
                        numList = new List<CalNum>();
 
                        //从该运算符后面,逐个扫描,获取该运算符的参数
                        //j表示已读取的参数个数
                        //m表示检测位置增量
                        int m = 0;
                        for (int j = 0; j < count; )
                        {
                            //如果找到数字,存为参数
                            if (valList[i + j + m + 1].type == ValType.Number)
                            {
                                numList.Add(valList[i + j + m + 1].num);
                                j++;
                            }
                            //如果是分隔符或左括号,检测位置增量加1,表示跳过该运算因子,继续检测
                            else if (valList[i + j + m + 1].OpeType == OpeType.Separator
                                || valList[i + j + m + 1].OpeType == OpeType.leftParenthesis)
                            {
                                m++;
                            }
                        }
 
                        //计算
                        num = CalOpeList.Calculate(valList[i].ope, numList);
                        //更新运算因子列表,count+m+2中的2表示运算符本身和右括号
                        ReplaceVal(num, count + m + 2, i);
                    }
                    #endregion
 
                    break;
 
                #endregion
 
            }//end switch
 
            if (!isSign)//如果不是正负号
            {
                break;//退出for循环
            }
        }
    }
    #endregion
 
    #region 删除处理完的优先级
    bool levelExists = false;//是否存在具有该优先级的运算符
    //逐个扫描运算因子,判断是否仍存在具有该优先级的运算符
    for (int i = 0; i < valList.Count; i++)
    {
        if (levelList[0] == valList[i].level)//存在
        {
            levelExists = true;
        }
    }
    if (!levelExists)//该优先级已处理完则删除它
    {
        levelList.RemoveAt(0);
    }
    #endregion
 
}
#endregion

  

四、结束语。

    没有什么高深的思想,我用最笨的办法实现了表达式计算。这个程序中用的最多的算法就是字符串查找,以及遍历数组。

 

    程序截图:


    源代码下载:点击下载

原文地址:http://www.cnblogs.com/s0611163/p/3504951.html

posted @   e天下小熊  阅读(295)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示