ExpressionUtils.java
8.1 KB
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
package com.skua.tool.util;
import lombok.extern.slf4j.Slf4j;
import java.util.*;
/**
* <pre>
* 表达式解析
* </pre>
*
* @author sonin
* @version 1.0 2022/7/22 上午8:14
*/
@Slf4j
public class ExpressionUtils {
/**
* 1. 将中缀表达式转成中缀字符串列表,方便遍历
*
* @param expression
* @return
*/
private static List<String> toInfixList(String expression) {
List<String> infixList = new ArrayList<>();
int i = 0;
StringBuilder stringBuilder = new StringBuilder();
while (i < expression.length()) {
if ('{' == expression.charAt(i)) {
// 保存遍历过程中产生的数字,{...}格式拼接成一个数
stringBuilder.delete(0, stringBuilder.length());
i++;
while (i < expression.length() && '}' != expression.charAt(i)) {
stringBuilder.append(expression.charAt(i));
i++;
}
infixList.add(stringBuilder.toString());
} else if (Character.isDigit(expression.charAt(i))) {
// 如果遇到数字,拼接成一个浮点类型的字符串
stringBuilder.delete(0, stringBuilder.length());
while (i < expression.length() && (Character.isDigit(expression.charAt(i)) || '.' == expression.charAt(i))) {
stringBuilder.append(expression.charAt(i));
i++;
}
infixList.add(stringBuilder.toString());
} else if ('+' == expression.charAt(i) || '-' == expression.charAt(i) || '*' == expression.charAt(i) || '/' == expression.charAt(i) || '(' == expression.charAt(i) || ')' == expression.charAt(i)) {
// 如果当前字符是 +-*/(),直接加入结果
infixList.add(expression.charAt(i) + "");
i++;
} else {
// 直接跳过,e.g: ' '
i++;
}
}
return infixList;
}
/**
* 2. 将中缀表达式字符串列表,转成后缀表达式字符串列表
*
* @param infixList
* @return
*/
public static List<String> toSuffixList(List<String> infixList) {
// 符号栈
Stack<String> operatorStack = new Stack<>();
// 在整个转换过程中,没有pop操作,在后面还要逆序输出,所以用list代替栈
List<String> suffixList = new ArrayList<>();
for (String item : infixList) {
if ("(".equals(item)) {
// 如果是左括号,入栈operatorStack
operatorStack.push(item);
} else if (")".equals(item)) {
// 如果是右括号,则依次弹出符号栈operatorStack栈顶的运算符,并压入suffixList,直到遇到左括号位置,将这一对括号消除掉
while (!"(".equals(operatorStack.peek())) {
suffixList.add(operatorStack.pop());
}
// 丢弃左括号,继续循环,也就消除了一对括号
operatorStack.pop();
} else if ("+".equals(item) || "-".equals(item) || "*".equals(item) || "/".equals(item)) {
// 此时,遇到的是加减乘除运算符
// 当前操作符优先级<=operatorStack的栈顶运算符的优先级,则将operatorStack的运算符弹出,并加入到suffixList中
while (!operatorStack.empty() && priority(operatorStack.peek()) >= priority(item)) {
suffixList.add(operatorStack.pop());
}
operatorStack.push(item);
} else {
suffixList.add(item);
}
}
// 将operatorStack中剩余的运算符依次弹出,并加入suffixList
while (!operatorStack.empty()) {
suffixList.add(operatorStack.pop());
}
return suffixList;
}
/**
* <pre>
* 直接将表达式转成后缀表达式字符串列表
* </pre>
*
* @param expression
* @author sonin
* @Description: TODO(这里描述这个方法的需求变更情况)
*/
public static List<String> toSuffixList(String expression) {
return toSuffixList(toInfixList(expression));
}
/**
* 对后缀表达式字符串列表进行计算
*
* @param suffixList
* @return
*/
public static double calculateSuffix(List<String> suffixList, Map<String, Double> expressionMap) {
Stack<Double> stack = new Stack<>();
for (String suffix : suffixList) {
double n1, n2;
switch (suffix) {
case "*":
n1 = stack.pop();
n2 = stack.pop();
stack.push(n1 * n2);
break;
case "/":
n1 = stack.pop();
n2 = stack.pop();
stack.push(n2 / n1);
break;
case "+":
n1 = stack.pop();
n2 = stack.pop();
stack.push(n1 + n2);
break;
case "-":
n1 = stack.pop();
n2 = stack.pop();
stack.push(n2 - n1);
break;
default:
if (expressionMap.containsKey(suffix)) {
stack.push(expressionMap.get(suffix));
} else if(DigitalUtils.isNumeric(suffix)) {
stack.push(Double.parseDouble(suffix));
}else{
log.warn("点位【"+ suffix + "】未匹配到值,使用默认值0");
stack.push(0.0);
}
break;
}
}
double v = stack.pop();
if(Double.isNaN(v) || Double.isInfinite(v)){
log.warn("表达式计算分母为0或出NAN,使用默认值0");
return 0D;
}
return v;
}
/**
* 符号优先级
*
* @param operator
* @return
*/
private static int priority(String operator) {
if ("+".equals(operator) || "-".equals(operator)) {
return 1;
}
if ("*".equals(operator) || "/".equals(operator)) {
return 2;
}
// 如果是左括号返回0
return 0;
}
/**
* 表达式结果
*
* @param expression
* @param expressionMap
* @return
*/
public static Double expressionResult(String expression, Map<String, Double> expressionMap) {
return calculateSuffix(toSuffixList(toInfixList(expression)), expressionMap);
}
/**
* 解析表达式指标
*
* @param expression
* @return
*/
public static List<String> parseExpression(String expression) {
List<String> codeList = new ArrayList<>();
int i = 0;
// 保存遍历过程中产生的{...},{...}格式拼接成一个指标
StringBuilder stringBuilder = new StringBuilder();
while (i < expression.length()) {
if ('{' == expression.charAt(i)) {
stringBuilder.delete(0, stringBuilder.length());
i++;
while (i < expression.length() && '}' != expression.charAt(i)) {
stringBuilder.append(expression.charAt(i));
i++;
}
codeList.add(stringBuilder.toString());
} else {
// 直接跳过
i++;
}
}
return codeList;
}
public static void main(String[] args) throws Exception {
String expression = "({a} + (( {b} + {c} ) * {d} ) - {e}) / 2.0";
Map<String, Double> expressionMap = new HashMap<String, Double>(5) {{
put("a", 2D);
put("b", 1D);
put("c", 1D);
put("d", 1D);
put("e", 1D);
}};
List<String> codeList = parseExpression(expression);
System.out.println(codeList);
double expressionResult = expressionResult(expression, expressionMap);
System.out.println(expressionResult);
}
}