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;
            }
        }

    }
时间: 2024-10-21 20:44:41

Flex版本的基于栈的表达式计算器的相关文章

基于语法分析器GOLD Parser开发的数学表达式计算器

最近发现一款文法分析神器,看完官网(http://goldparser.org/)的介绍后感觉很犀利的样子,于是就拿来测试了一番,写了一个数学表达式分析的小程序,支持的数学运算符如下所示:常规运算:+ - * / ^ sqrt sqrt2(a,b) pow2(a) pow(a,b)三角函数:sin cos tan cot asin acos atan acot指数对数:log2(a) log10(a) ln(a) logn(a,b) e^最大最小:max(a,b,...) min(a,b,...

基于对象编程与面向对象编程(表达式计算器3)

基于对象编程与面向对象编程 我们的最终目的是用C++设计一个面向对象的表达式计算器,所以非常有必要弄清楚,什么是基于对象编程和面向对象的编程.而要弄清楚这一点,又要先弄明白什么是值语言,什么是对象语义 值语义:对象的拷贝与原对象无关,拷贝后与原对象脱离关系,互不影响.这种拷贝叫深拷贝.拷贝之后脱离关系,只要在拷贝的时候都为对象分配内存空间就行了.某种些情况下算是一种对资源的浪费 值语义例子 class Test { private: int * pNum_; public: Test(int n

C#编程(七十六)----------使用指针实现基于栈的高性能数组

使用指针实现基于栈的高性能数组 以一个案例为主来分析实现方法: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace 基于堆栈的数组 { class Program { static void Main(string[] args) { int[] i = new int[10]; Console.W

虚拟机字节码操作引擎-----基于栈的字节码解释引擎

虚拟机调用方法可以有解析和分派两种方式,那么虚拟机是如何执行方法中的字节码指令的? 1.解释执行   谈是解释执行还是翻译执行没有意义了,只有确定了某种具体的java实现版本和执行引擎运行模式时,谈解释执行还是编译执行才比较贴切. 如今,基于物理机.java虚拟机,或者非Java的其他高级语言虚拟机的语言,大多都会遵循这种基于现代经典编译原理的思路,在执行前先对程序源码进行词法分析和语法分析处理,把源码转化为抽象语法树 .对于一门具体语言的实现来说,词法分析.语法分析以致后面的优化器和目标代码生

算法手记(2)Dijkstra双栈算术表达式求值算法

这两天看到的内容是关于栈和队列,在栈的模块发现了Dijkstra双栈算术表达式求值算法,可以用来实现计算器类型的app. 编程语言系统一般都内置了对算术表达式的处理,但是他们是如何在内部实现的呢?为了了解这个过程,我们可以自行搭建一套简易的算术表达式处理机制,这里就用到栈特性和本篇提到的Dijkstra算法. 概述:     算术表达式可能是一个数.或者是由一个左括号.一个算术表达式.一个运算符.另一个算术表达式和一个右括号组成的表达式.为了简化问题,这里定义的是未省略括号的算术表达式,它明确地

基于逆波兰表达式的公式解析器-算法和思路(一)

背景: 近期项目须要自己完毕Excel的公式解析和求值,在Java中能够使用POI解析Excel公式然后求值.可是项目须要JS端和Java后端均须要支持公式解析,所以就须要自己写一套了.事实上公式解析器整体上并不复杂.原理使用逆波兰表达式就可了. 难点: 1. 针对复杂的用户输入环境解析公式,须要注意公式书写不规范.大写和小写.空格等问题,甚至公式出错的推断. 2. 须要解决函数扩展.函数运行等问题. 3. 须要解决地址.地址范围取数,求值问题. 4. 处理括号带来的优先级提升. 5. 解决公式

Linux (x86) Exploit系列之三 Off-By-One 漏洞 (基于栈)

Off-By-One 漏洞 (基于栈) 原文地址:https://bbs.pediy.com/thread-216954.htm 什么是off by one? 将源字符串复制到目标缓冲区可能会导致off by one 1.源字符串长度等于目标缓冲区长度. 当源字符串长度等于目标缓冲区长度时,单个NULL字节将被复制到目标缓冲区上方.这里由于目标缓冲区位于堆栈中,所以单个NULL字节可以覆盖存储在堆栈中的调用者的EBP的最低有效位(LSB),这可能导致任意的代码执行. 一如既往的充分的定义,让我们

关于栈实现综合计算器的代码实现和讲解

1.先思考下面的表达式怎么实现 先思考下面的表达式如何计算,虽然可以直接计算,但是怎么实现的呢? 请输入一个表达式 计算式:[7*2*2-5+1-5+3-3] 我们可以用栈来实现,怎么实现?先看一个复杂的实现方式:中缀表达式实现 2.什么是中缀表达式? 中缀表达式就是人们生活中的计算方法,比如上面的表达式,我们怎么算?7*2*2-5+1-5+3-3,在计算机中也是这样,我们先看如何实现它 3.中缀表达式计算器代码实现和讲解 3.1先定义一个栈(自定义) //先创建一个栈,直接使用前面创建好 //

表达式计算器类的设计5(面向对象的表达式计算器8)

计算器的github下载地址:https://github.com/ljian1992/calculator 概述 表达式计算器的类基本已经设计完成了,由于在程序运行的时候总会有这样那样的异常,例如:a +2, a没有初始化,对于异常的管理一般而言是需要自定义异常类.这个自定义异常类也是在继承了系统已经定义好的exception类,然后再重新定义内容. 异常的种类 语法异常---->SyntaxError类 赋值时左操作数不是变量:1 = 2; 缺少括号:1 + (2*2 不认识的函数: 函数缺