关系表达式的计算

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

关系表达式的计算的相关文章

第五章 循环和关系表达式

第五章  循环和关系表达式 5.1  for循环 5.1.1  for循环的使用 For循环的组成部分完成下面4个步骤: 1)        设置初始值: 2)        执行测试,看看循环是否应当继续运行: 3)        执行循环体: 4)        更新用于测试的值. For循环的形式如下: for (init-expresstion; test-expresstion; update-expresstion) body-statement 说明: 1)        C++将

c++primerplus(第六版)编程题——第5章(循环和关系表达式)

声明:作者为了调试方便,每一章的程序写在一个工程文件中,每一道编程练习题新建一个独立文件,在主函数中调用,我建议同我一样的初学者可以采用这种方式,调试起来会比较方便. (具体方式参见第3章模板) 1. 编写一个要求用户输入两个整数的程序.该程序将计算并输出这两个整数之间(包括这两个整数)所有整数的和. #include <iostream> using namespace std; void cprimerplus_exercise_5_1() { cout << "Pl

续前篇-关于逆波兰表达式的计算

相对于逆波兰表达式的转换,逆波兰表达的计算可谓简单不少. 具体计算方法参考:http://www.cnblogs.com/vpoet/p/4659546.html 这里也大致梳理一下: 1.新建一个栈将逆波兰表达式的数字依次压入栈中 2.当遇到运算符时,出栈两个数同时将运算结果压栈 3.重复步骤2直到计算计算,栈中的元素即为逆波兰表达式的计算结果. 实现如下: 1 #include <iostream> 2 #include <stack> 3 using namespace st

表达式的计算(中缀表达式转为后缀表达式或逐步计算)

算数表达式的计算,也是很基础的一个问题.花了点时间写了下. 网上很多正确代码.但没有详细说明.虽然不复杂,但是还是写详细点.只有仔细思考过.问题才会在头脑中,觉得简单. 基本有2种方法. 1)中缀表达式转为后缀表达式,是最简洁有力的方法. 2)符合人的计算思路的逐步方法,不推荐使用,只适合锻炼下逻辑能力. 一.中缀表达式转为后缀表达式,是最简洁有力的方法. //更简洁通用的算法,就是把中缀表达式转换为后缀表达式.后缀表达式:不包含括号,运算符放在两个运算对象的后面. //一,无括号的n级符号算法

《C++ Primer Plus》第5章 循环和关系表达式 学习笔记

C++提供了3种循环: for 循环. while 循环 和 do while 循环 .如果循环测试条件为 true 或非零,则循环将重复执行一组指令: 如果测试条件为 false 或 0 , 则结束循环. for 循环 和 while 循环都是入口条件循环,这意味着程序将在执行循环体中的语句之前检查测试条件.do while 循环是出口条件循环,这意味若其将在执行循环体中的语句之后检査条件.每种循环的句法都要求循环体由一条语句组成.然而, 这条语句可以是复合语句,也可以是语句块(由花括号括起的

后缀表达式的计算

/** * 后缀表达式的计算 * * 使用栈来保存结果 * * 1.从左向右逐一检查后缀表达式中的每一个字符 * 2.遇到数字直接push入栈 * 3.遇到操作符,就从栈中弹出两个数参与运算,将结果保留在栈中,如果操作符是 /,-或者^ * 号,则后弹出的数是第一个运算数 * 4.最后的结果保留在栈中**/ import java.util.Stack; public class calc { public double calculate(String postfix){ Stack<Doub

运用栈把算术表达式+,-,*,/,%(中缀表达式)转换成后缀表达式并且计算出值

原理: 1.首先判断是数值还是符号,如果是数值放进字符数组以#表示结束, 2.如果是符号,放进栈, 3.每个符号之间要比较优先级,如果栈顶符号优先级低,符号进栈,如果相等(即“(” “)”)出栈,栈顶符号优先级高,栈顶元素出栈进入字符数组,得到后缀表达式 4.计算后缀表达式,判断是数字还是符号.直到遇到符号,将前面的数字计算后放进栈,一直重复,知道“\0” 代码(局限用整数,因为有模运算,若要任何类型的代码,我的blog有) 1 #include <stdio.h> 2 #include &l

使用栈完成算术表达式的计算

前言:本篇文章讲解如何利用栈,完成一个简单的算术表达式的计算过程.为了简单起见,首先假设操作数是整数,而运算符为四种类型:+.-.*./ 基本思路:为了完成算术表达式的计算,用到了两个栈,一个用于存放操作数,另一个用于存放操作符. 假设:程序中定义了两个栈:operandStack(用来存放操作数).operatorStack(用于存放操作符). 在处理操作数和操作符之前,首先将它们压入栈中.当要处理一个操作符时,从operatorStack中将它弹出,然后将它应用在来自operandStack

关系表达式的使用

利用关系运算符连接的式子成为关系表达式. 关系运算就是比较运算符号(6个:== .!=. > .<. >=. <=) public class C2_8 {    public static void main(String args[])     {         boolean x,y;        double a,b;         a=12.56;         b=233.23;         x=(a!=b);         y=(a==b);