Flex版本的基于栈的表达式计算器

    /**
     * 表达式计算器,输入数学表达式的字符串,输出计算结果的数值
     * 1.扫描表达式,将运算符与运算数分别入栈,
     * 2.运算符入栈前先与上一个运算符进行优先级比较,如果当前运算符优先级低于或等于前一个运算符,
     * 则将前一个运算符和对应的运算数出栈运算,否则运算符直接入栈
     * @author lijy
     */
    public class ExpressionCaculator
    {        
        /**
         * 运算数栈
         * */
        private var numberStack:Array;
        
        /**
         * 运算符栈
         * */
        private var operatorStack:Array;
        
        /**
         * 构造函数
         */
        public function ExpressionCaculator(){}
        
        /**
         * 表达式计算器
         * @expression 表达式
         * @return 计算结果,NaN表示格式错误或存在不支持的运算符
         * */
        public function caculate(expression:String):Number{
            
            //去除空格
            var arr:Array = expression.split(' ');
            expression = '';
            for each(var item:String in arr){
                if(item!=' ')expression+=item;
            }
            
            //初始化栈
            numberStack = new Array();
            operatorStack = new Array();
            
            //遍历表达式
            for(var i:int=0; i<expression.length; i++){
                var index:int = getNextNumberEndIndex(expression,i);
                if(index>i){
                    //获取运算数
                    var data:Number = Number(expression.substr(i,index-i));
                    if(isNaN(data)){
                        //表达式有误返回NaN
                        return NaN;
                    }else{
                        //运算数入栈
                        numberStack.push(data);
                        i=index-1;
                    }
                }else{
                    //获取运算符,并调用出栈运算循环
                    var nextOperator:String = expression.substr(i,1);                    
                    var success:Boolean = this.calculateLoop(nextOperator)
                    if(!success){
                        //运算过程中出现不支持的操作符
                        return NaN;
                    }else if(nextOperator!=')'){
                        //操作符入栈,右括号除外
                        operatorStack.push(nextOperator);
                    }
                }
            }
            
            //最后调用出栈运算循环,计算还没有算完的部分
            var success:Boolean = this.calculateLoop()
            if(!success){
                //运算过程中出现不支持的操作符
                return NaN;
            }else{
                //返回计算结果
                return numberStack[0];
            }
        }
        
        /**
         * 出栈运算循环:
         * 循环出栈之前的运算符与下一个即将入栈的运算符做优先级对比,
         * 若优先级高于下一个则进行计算,若为括号则根据情况做括号合并或跳出计算
         * @nextOperator 下一个即将入栈的运算符,用于跟之前的运算符做优先级对比或括号消除
         * @return 计算是否成功,如果存在不支持的运算符将返回NaN
         * */
        private function calculateLoop(nextOperator:String=')'):Boolean{
            //返回结果初始值:是否存在不支持的运算符
            var result:Boolean=true;
            //获取下一个运算符的优先级
            var nextPriority:Number = getOperatorPriority(nextOperator);
            //进入运算循环
            while(operatorStack.length>0){
                var lastOperator:String = operatorStack[operatorStack.length-1];
                var lastPriority:Number = getOperatorPriority(lastOperator);
                if(isNaN(lastPriority) || isNaN(nextPriority)){
                    //存在不支持的运算符
                    result = false;
                    break;
                }
                if(nextPriority > lastPriority){
                    //优先级大于之前的运算符则不运算,跳出循环
                    result = true;
                    break;
                }else if(lastOperator=='('){
                    //如果上一个运算符是左括号:
                    //1.下一个运算符是右括号,那么左右括号抵消,运算符出站并跳出运算循环
                    //2.下一个运算符不是右括号,那么左括号保留,跳出运算循环
                    if(nextOperator==')')operatorStack.pop();
                    result = true;
                    break;
                }else{ 
                    //其他情况出站运算并循环
                    result = popAndCalculate();
                    if(result==false){
                        break;
                    }
                }
            }
            return result;
        }
        
        /**
         * 出栈最后一个运算符和对应的运算数进行运算,将运算结果入栈
         * @return 运算异常返回false,正常返回true
         * */
        private function popAndCalculate():Boolean{
            if(numberStack.length<2 || operatorStack.length<1){
                //至少要有两个运算数和一个运算符
                return false;
            }else{
                var lastOperator:String = operatorStack.pop() as String;
                var num1:Number = numberStack.pop() as Number;
                var num2:Number = numberStack.pop() as Number;
                switch(lastOperator){
                    case '*':
                        numberStack.push(num2*num1);
                        break;
                    case '/':
                        numberStack.push(num2/num1);
                        break;
                    case '+':
                        numberStack.push(num2+num1);
                        break;
                    case '-':
                        numberStack.push(num2-num1);
                        break;
                }
                return true;
            }
        }
        
        /**
         * 从指定下标位置开始获取下一个运算数结束的下标位置,注意判断减号和负号
         * @expression 表达式
         * @startIndex 判断的起始下标位置
         * @return 下一个运算数结束的下标位置,若返回值与startIndex相等说明下一个字符是操作符不是运算数
         * */
        private static function getNextNumberEndIndex(expression:String, startIndex:int):int{
            var i:int=startIndex;
            //判断减号和负号,表达式的第一个字符或者左括号前的第一个字符如果为-,则判定为负号,否则为减号
            if(expression.charAt(i)=='-'){
                if(i==0 || expression.charAt(i-1)=='('){
                    i++;
                }else{
                    return i;
                }
            }
            //遍历数字和小数点
            for(i; i<expression.length; i++){
                var ascii:Number = expression.charCodeAt(i);
                if((ascii>=48&&ascii<=57) || ascii==46){
                    continue;
                }else{
                    return i;
                }
            }
            return i;
        }
        
        /**
         * 获取运算符优先级
         * @operator 运算符
         * @return 优先级
         * */
        private static function getOperatorPriority(operator:String):Number{
            switch(operator){
                case '(':
                    return 3;
                case '*':
                case '/':
                    return 2;
                case '+':
                case '-':
                    return 1;
                case ')':
                    return 0;
                default:
                    return NaN;
            }
        }

    }

 

posted @ 2015-12-24 10:16  kuntaljy  阅读(302)  评论(0编辑  收藏  举报