近期在做一个项目,涉及到一些简单的规则匹配。规则的判定条件可以用关系表达式描述,形如(P1|P2)&(P3|P4)。其中&是与,|是或,P1-P4是Pattern,具体的匹配条件,返回值是True或者False。为计算此表达式的值,采用中序转后序再计算表达式的值。
1. 后序表达式的生成
中序表达式转后序表达式算法:
1. 用&|()对原表达式进行拆分,得到List<String>。 2. 从前往后遍历该List: (1)如果是一个pattern,则入栈。 (2)如果是左括号(,也入栈。 (3)如果是右括号: (a)如果此时栈为空,则表示表达式解析异常,报警并退出。 (b)如果栈不为空,则依次pop栈顶元素,直到匹配到左括号(。如果没有左括号(的匹配,则表达式依次,报警并退出。 (4)如果是&和|: (a)如果栈为空,直接入栈。 (b)如果栈不为空,依次出栈直到匹配左括号(左括号不出栈)。再把操作符入栈。 3、所有的pattern和操作符都入栈以后,把栈中所有元素依次出栈,就得到后序表达式。 |
参考代码:
List<String> postfix = new ArrayList<String>(); Stack<String> stack = new Stack<String>(); String delims = "&|()"; // 支持的操作符 StringTokenizer st = new StringTokenizer(rule, delims, true); while (st.hasMoreTokens()) { String tk = st.nextToken(); if (!delims.contains(tk)) { // pattern,直接入栈 postfix.add(tk); } else if (tk.equals("(")) { // 左括号,入栈 stack.push(tk); } else if (tk.equals(")")) { if (stack.empty()) { // 碰到右括号,如果栈为空,解析异常 throw new RuleException("parseRule Error!"); } String val = stack.pop(); // 如果栈不为空,依次出栈直到匹配左括号 while (!val.equals("(")) { postfix.add(val); if (!stack.empty()) { val = stack.pop(); } else break; } if (stack.empty() && !val.equals("(")) { // 如果匹配不到左括号,解析异常 throw new RuleException("parseRule Error!"); } } else if (tk.equals("&") || tk.equals("|")) { if (stack.empty()) { // 碰到操作符,如果栈空,则直接入栈 stack.push(tk); } else { // 如果栈不为空,依次出栈直到匹配左括号 while (!stack.empty() && !stack.lastElement().equals("(")) { postfix.add(stack.pop()); } // 操作符入栈 stack.push(tk); } } } // 所有的pattern和操作符匹配完毕,把堆栈中还有的数据依次出栈 while (!stack.empty()) { postfix.add(stack.pop()); } System.out.println("Original Rule:" + rule); System.out.println("Postfix Rule: " + postfix.toString());
2. 后序表达式的计算
后序表达式的计算算法:
1. 从前往后遍历中序表达式: (1)如果是&|操作符,则pop两个字段r1和r2,计算r1&r2或r1|r2的值r3,并将r3入栈。 (2)如果是pattern,则计算pattern的匹配结果True Or False,并将结果入栈。 2、中序表达式便利完毕,栈中只有1个元素,即为表达式结果。 |
参考代码:
Stack<Boolean> stack = new Stack<Boolean>(); for (String str : this.postfix) { if (str.equals("&")) { // pop两个pattern,计算 boolean r1 = stack.pop(); boolean r2 = stack.pop(); stack.push(r1 && r2); } else if (str.equals("|")) { // pop两个pattern,计算 boolean r1 = stack.pop(); boolean r2 = stack.pop(); stack.push(r1 || r2); } else { // 计算pattern的值,并push到stack Pattern ptn = this.patterns.get(str); stack.push(ptn.judge(fact)); } } if (stack.size() == 1) { return stack.pop(); } else { throw new RuleException("judge failed: postfix error!"); }