关系表达式的计算

近期在做一个项目,涉及到一些简单的规则匹配。规则的判定条件可以用关系表达式描述,形如(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!");
}

 

posted @ 2015-08-30 22:50  如玉暖阳  阅读(614)  评论(0编辑  收藏  举报