最近在研究一个配置解析相关功能, 解析是针对一些规则进行, 考虑到规则的多样性,准备采用逆波兰表达式来进行拆解,然后再单独进行原子化处理。
上面说的规则其实就是一个公式,公式可以分为两部分:
- 运算量
- 运算符
运算量比较号理解, 就是A+B+C公式里的ABC,运算符相对复杂一些,对于数学四则运算来说就是+、-、*、/ ,其实如果拓展一下, 运算符可以是现有的逻辑运算符号比如:&、|、!、^ 等,也可以自定义一个特殊含义的运算符,比如说 = 代表两边都需要成立,>代表左边成立,右边也需要成立,<代表右边成立,左边也都成立,这是从运算符自生属性上来解释。不过运算符还需要考虑它们的作用范围,我大概将其分为三类:
- ( ) 括号类的, 作用域为前后对于的一组为范围
- 单元组范围:该类运算符只需要一个运算量就可以参与运算
- 二元组范围:该类运算符需要两个运算量参与才能进一步运算
- 三元及多元组:这类我暂时没有想明白
下面是一个对逆波兰表达式的JAVA实现代码,需要注意的是:
- 仅仅支持单字符运算符与小括号(不支持中括号、大括号)
- 可以自定义符号的优先级
- 刚刚出土的代码, 所以性能问题及bug来了不要怕
计划,针对该逆波兰表达式,再封装对其的运算量及运算符的操作,这个以后再更新。
package rule;
import java.util.*;
/**
* 逆波兰表达式生成的array deque
* <li><b>仅仅支持单字符运算符与小括号(不支持中括号、大括号)</b></li>
* <li>可以自定义符号的优先级</li>
*
* @author 54117
*/
public class RPN {
Queue<String> rpn = new ArrayDeque<>();
public static HashMap<String, Integer> prioritizedOps = new LinkedHashMap<>(16);
static {
prioritizedOps.put("(", 1000);
prioritizedOps.put(")", 1000);
prioritizedOps.put("!", 1);
prioritizedOps.put("^", 2);
prioritizedOps.put("&", 3);
prioritizedOps.put("|", 4);
// prioritizedOps.put("=>", 5);
// prioritizedOps.put("<=", 6);
// prioritizedOps.put("<=>", 7);
prioritizedOps.put("*", 10);
prioritizedOps.put("/", 10);
prioritizedOps.put("+", 20);
prioritizedOps.put("-", 20);
}
public static RPN rpn(String rule) {
if (null == rule || "".equals(rule)) {
return null;
}
RPN re = new RPN();
Queue<String> rpn = re.rpn;
Stack<String> optStack = new Stack<>();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < rule.length(); i++) {
String s = String.valueOf(rule.charAt(i));
boolean isOpt = prioritizedOps.containsKey(s);
if (isOpt) {
//
if (sb.length() > 0) {
String preV = sb.toString();
sb.delete(0, sb.length());
rpn.offer(preV);
}
if ("(".equals(s)) {
optStack.push(s);
} else if (")".equals(s)) {
while (!optStack.isEmpty()) {
String ss = optStack.pop();
if ("(".equals(ss)) {
break;
}
rpn.offer(ss);
}
} else {
// 比较
Integer optP = prioritizedOps.getOrDefault(s, 10000);
if (!optStack.isEmpty()) {
//判断是否在比较的过程中入栈
boolean pushed = false;
while (!optStack.isEmpty()) {
Integer lstP = prioritizedOps.getOrDefault(optStack.peek(), 10000);
// 优先级高,则入栈
if (optP < lstP) {
optStack.push(s);
pushed = true;
break;
} else {
//否则退栈输出
rpn.offer(optStack.pop());
}
}
if (!pushed) {
optStack.push(s);
}
} else {
//栈为空,直接入栈
optStack.push(s);
}
}
} else {
sb.append(s);
}
}
if (sb.length() > 0) {
String preV = sb.toString();
rpn.offer(preV);
}
while (!optStack.isEmpty()) {
rpn.offer(optStack.pop());
}
return re;
}
@Override
public String toString() {
return rpn.toString();
}
// test
public static void main(String[] args) {
// [A, B, +, C, D, -, *]
System.out.println( RPN.rpn("((A+B))*(C-D)").toString());
// [A, B, +, C, *, D, -]
System.out.println( RPN.rpn("((A+B))*C-D").toString());
// [A, B, +, C, *, D, -]
System.out.println( RPN.rpn("(((A+B))*C)-D").toString());
// [A, !, B, C, &, |]
System.out.println( RPN.rpn("!A|B&C").toString());
//[A, B, !, |, C, |, D, E, ^, |]
System.out.println( RPN.rpn("A|!B|C|D^E").toString());
}
}
参考百度百科关于逆波兰表达式的流程图