一个非常酷的Js计算器(加减乘除,浮点,以及括号运算,四则混合运算)

github源代码链接 : https://github.com/johnnylei/calculate

<!DOCTYPE html>
<html>
    <head>
        <title>calculate</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link type="text/css" href="calculate.css" rel="stylesheet">
        <script type="text/javascript" src="calculate.js"></script>
    </head>
    <body οnlοad="pageLoad()">
<!--        <p>1+(2*3)-(((2*3)*((1+2)/3)-3*6)-(3*6))+3</p>
        <p>1.1+(2.1*3)-(((2.2*3)*((1.1+2.2)/3.3)-3.4*6)-(3.5*6))+3.6</p>-->
        <div id="calculate">
            <input type="text" id="show" value = '0' readonly>
            <div id="keyboard">
                <table>
                    <tr>
                        <td class = "ACkeyButton">AC</td>
                        <td class="keyButton">+</td>
                        <td class="keyButton">-</td>
                        <td class="keyButton">*</td>
                    </tr>
                    <tr>
                        <td class="keyButton">1</td>
                        <td class="keyButton">2</td>
                        <td class="keyButton">3</td>
                        <td class="keyButton">/</td>
                    </tr>
                    <tr>
                        <td class="keyButton">4</td>
                        <td class="keyButton">5</td>
                        <td class="keyButton">6</td>
                        <td class="keyButton">(</td>
                    </tr>
                    <tr>
                        <td class="keyButton">7</td>
                        <td class="keyButton">8</td>
                        <td class="keyButton">9</td>
                        <td class="keyButton">)</td>
                    </tr>
                    <tr>
                        <td class="keyButton">0</td>
                        <td class="keyButton">.</td>
                        <td id="calculateResult">=</td>
                        <td id = "deleteNumber">del</td>
                    </tr>
                </table>
            </div>
        </div>
    </body>
</html>

/* 
 * 这是一个功能比较强大的计算机
 * 运算法 包括了 加减乘除以及括号
 * 整个过程是面向对象实现的
 */


/**
 * 这是一个计算机类
 * 在点击了"AC"之后,会触发clean(),把Input框里面的显示成0,另外把表达式this.express清空
 * 在点击了“del”之后,会触发deleteNumber(),把表达式的最后一位删除,并且显示在Input框里面
 * 在点击普通字符,既标签属性class=keyButton,就会触发showExpresson,会把你所输入的字符显示在input框里面,然后把表达式赋值this.expression += expression
 * 在点击“=”之后,就会调用calculateResult()方法进行计算;计算大致分为6步
 * 1.验证是否有非法的运算符
 * 2.验证是否有非法的浮点
 * 3,验证括号使用是否正确
 * 4.去掉表达式中的括号
 * 5.去掉表达式中的乘法和除法
 * 6.现在的表达式里面只有加法和减法运算符,接下来,我们只要进行加减法运算既可以得到最后的答案了
 * @returns {Calculate}
 */
function Calculate() {
    this.showArea = document.getElementById("show");
    this.expression = '';
    this.clean = function() {
        this.showArea.value = '0';
        this.expression = '';
    };
    this.deleteNumber = function() {
        this.expression = this.expression.substring(0,this.expression.length-1);
        this.showArea.value = this.expression;
    };
    this.showExpression = function(expression) {
        this.expression += expression;
        this.showArea.value = this.expression;
    };
    /**
     * first step we should remove bracket
     * second step we should remove Multiplic and Division
     * the last step just remove plus and minus,and then result out
     * @returns {undefined}
     */
    this.calculateResult = function() {
//        this.expression = "1.1+(2.1*3)-(((2.2*3)*((1.1+2.2)/3.3)-3.4*6)-(3.5*6))+3.6";
        var wrongMessage = "this expression is invalid";
        if (!this.checkOperator(this.expression) || !this.checkFloat(this.expression)) {
            this.showArea.value = wrongMessage;
            this.expression = '';
            return ;
        }
        if(this.hasBracket(this.expression)) {
            if (!this.checkBracket(this.expression)) {
                this.showArea.value = wrongMessage;
                this.expression = '';
                return ;
            }
            this.expression = this.removeBracket(this.expression);
        }


        if (this.hasMultiplicOrDivision(this.expression)) {
            this.expression = this.removeMultiplicOrDivision(this.expression);
        }
        if(this.hasPlusOrMinus(this.expression)) {
            this.expression = this.plusOrMinus(this.expression);
        }
        this.showArea.value = this.expression;
        this.expression = '';
    };
    /**
     * 
     * @param {type} expression
     * @returns {undefined|Boolean}
     * 检查运算符是否合法,第一个字符是除“-”意外的运算符都是非法的,最后一个字符是运算符,也是非法的;
     * 检查是否含有不合法的多运算符 “**”,“*\/”,"*+","*-","+*","++","+\/"以及两以上的连续运算符都是不允许的
     * 在多运算符里面除了 “--”,“+-”都是不合法的多运算符
     */
    this.checkOperator = function(expression) {
        /**
         * (^[\+\*\/])|([\+\-\*\/]$) 匹配首字符或是最后一个字符是不是运算符
         * ([\+\-\*\/][\+\*\/]+) [+,*,-,/]搭配一个或是多个[+,*,/]
         * ([\*\/](\-)+) [*,/]搭配一个或是多个[-]
         * ([\+\-](\-){2,}) [+,-]搭配两个以上的[-]
         * @type RegExp
         */
      var reg = /(^[\+\*\/])|([\+\-\*\/]$)|([\+\-\*\/][\+\*\/]+)|([\*\/](\-)+)|([\+\-](\-){2,})/;  
      if(reg.test(expression)) {
          return false;
      }
      return true;
    };
    /**
     * 
     * @param {type} expression
     * @returns {undefined}
     * 检查“.”是否在正确位置,".+","+.","^.",".$","2.2.3.4.5","..","..."都是不允许的。
     */
    this.checkFloat = function (expression) {
        /**
         * (^\.)|(\.$) expression以.开头或结尾
         * ([\+\-\*\/]\.)|(\.[\+\-\*\/]) expression出现".+","+."等情况
         * ((\d+\.+){2,}\d*) expression出现"2.2.3.4.5","..","..."等情况
         */
        var reg = /(^\.)|(\.$)|([\+\-\*\/]\.)|(\.[\+\-\*\/])|((\d+\.+){2,}\d*)/;
        if (reg.test(expression)) {
            return false;
        }
        return true;
    };
    /**
     * 
     * @param {type} expression
     * @returns {@this;@call;removeBracket}
     * make sure the expression has bracket
     */
    this.hasBracket = function(expression) {
        var hasBraketReg = /(\(|\))/; //查看表达expression中是否有();
        if (hasBraketReg.test(expression)) {
            return true;
        }
        return false;
    };
    /**
     * 检查表达式中的输入的括号输入正确;
     * 1.括号必须与运算符号连接在一起 既“3(”,“(*3”,“3*)”,“)3”,".)",".(","(.",").",是不允许的
     * 2.左括号的数量必须等于右括号的数量
     * @param {type} expression
     * @returns {undefined}
     */
    this.checkBracket = function(expression) {
        var reg = /([\d\.]\()|(\)[\d\.])|(\([\+\-\*\/\.])|([\+\-\*\/\.]\))/;
        if (reg.test(expression)) {
            return false;
        }
        var leftBracket = 0, rightBracket = 0;
        for (var i = 0; i < expression.length; i++) {
            if (expression.charAt(i) === "(") {
                leftBracket++;
            } else if(expression.charAt(i) === ")") {
                rightBracket++;
            }
        }
        if (!(leftBracket === rightBracket)) {
            return false;
        }
        return true;
    };
    /**
     * 
     * @param {type} expression
     * remove bracket;
     * @returns {undefined}
     */
    this.removeBracket = function(expression) {
        var regMatch = /\([^\(\)]+\)/g; //这个正则表达式匹配最里面的一层括号,既(这里面是不能包含“(”或是“)”的)
        var childExpression = expression.match(regMatch);
        var mySign = "&mySign&"; //用一个特殊标记记录等会需要替换的位置
        var replaceExpression = expression.replace(regMatch,mySign);
        var subExpression = "";
        for(var i = 0; i < childExpression.length; i++) {
            subExpression = childExpression[i].substring(1,childExpression[i].length-1);
            if (this.hasMultiplicOrDivision(subExpression)) {
                subExpression = this.removeMultiplicOrDivision(subExpression);
            }
            if (this.hasPlusOrMinus(subExpression)) {
                subExpression = this.plusOrMinus(subExpression);
            }
            replaceExpression = replaceExpression.replace(mySign,subExpression);
        }
        expression = replaceExpression;
        if(this.hasBracket(expression)) {
            expression = this.removeBracket(expression);
        } else {
            return expression;
        }
        return expression;
    };
    
    /**
     * 
     * @param {type} expression
     * @returns {@this;@call;removeMultiplicOrDivision}
     * make sure the expression with Multiplic Or Division
     */
    this.hasMultiplicOrDivision = function(expression) {
        var hasMultiplicOrDivisionReg =  /(\*|\/)/;
        if (hasMultiplicOrDivisionReg.test(expression)) {
            return true;
        };
        return false;
    };
    /**
     * 
     * @param {type} expression
     * remove Multiplic and Division
     * @returns {unresolved}
     */
    this.removeMultiplicOrDivision = function(expression) {
//        var expression = "1-13*2+3*456/3*15*8/5*4-50-40+32*2/16"; //test data
        var regMatch = /((\d+\.?\d*)(\*|\/))+(\d+\.?\d*)/g;
        var childResult = "";
        var childExpression = expression.match(regMatch);
        var mySign = "&mySign&"; //用一个特殊标记记录等会需要替换的位置
        var replaceExpression = expression.replace(regMatch,mySign);
        for(var i = 0; i < childExpression.length; i++) {
            childResult = this.multiplicOrDivision(childExpression[i]);
            replaceExpression = replaceExpression.replace(mySign,childResult);
        }
        expression = replaceExpression;
        return expression;
    };
    this.multiplicOrDivision = function(expression) {
        var regNumber = /\d+\.?\d*/g;
        var regOperator = /(\*|\/)/g;
        var arrNumbers = expression.match(regNumber);
        var arrOperators = expression.match(regOperator);
        
        var calResult = parseFloat(arrNumbers[0]);
        for (var i = 0; i < arrOperators.length; i++) {
            if (arrOperators[i] === '*') {
                calResult *= parseFloat(arrNumbers[i+1]);
            } else {
                calResult /= parseFloat(arrNumbers[i+1]);
            }
        }
        return calResult;
    };
    
    this.hasPlusOrMinus = function(expression) {
        var hasPlusOrMinusReg =  /(\+|\-)/;
        if (hasPlusOrMinusReg.test(expression)) {
            return true;
        };
        return false;
    };
    /**
     * 
     * @param {type} expression
     * this is the last step , just has plus or minus , after we done this step, the result out
     * @returns {Calculate.plusOrMinus.calResult}
     */
    this.plusOrMinus = function(expression) {
        /**
         *  如果第一个字符是“-”号,就在expression前面加上一个0即可
         */
        if (expression.charAt(0) === "-") {
            expression = 0 + expression;
        }
        var doubleMinusReg = /\-\-/;  //减去一个负数,等于加一个正数
        if (doubleMinusReg.test(expression)) {
            expression = expression.replace(doubleMinusReg,"+");
        }
        doubleMinusReg = /\+\-/;  //加上一负数,等于减去一个正数
        if (doubleMinusReg.test(expression)) {
            expression = expression.replace(doubleMinusReg,"-");
        }
        var regNumber = /\d+\.?\d*/g;
        var regOperator = /(\+|\-)/g;
        var arrNumbers = expression.match(regNumber);
        var arrOperators = expression.match(regOperator);
        
        var calResult = parseFloat(arrNumbers[0]);
        for (var i = 0; i < arrOperators.length; i++) {
            if (arrOperators[i] === '+') {
                calResult += parseFloat(arrNumbers[i+1]);
            } else {
                calResult -= parseFloat(arrNumbers[i+1]);
            }
        }
        return calResult;
    };
}


function pageLoad() {
    var calculate = new Calculate();
    var ACkeyButton = document.getElementsByClassName("ACkeyButton");
    ACkeyButton[0].onclick = function() { 
        calculate.clean();
    };
    var deleteNumber = document.getElementById("deleteNumber");
    deleteNumber.onclick = function() { 
        calculate.deleteNumber();
    };
    var calculateResult = document.getElementById("calculateResult");
    calculateResult.onclick = function () {
        calculate.calculateResult();
    };
    var keyButton = document.getElementsByClassName("keyButton");
    for (var i in keyButton) {
        /**
         *这个写法是错误的,因为i没有被lock住
         *在这个循环执行以后,点击keyButton的时候,i才获得具体的数值
         *因为点击的时候i才真正的获得数值
         */
//        keyButton[i].onclick = function() {
//            return calculate.showExpression(keyButton[i].innerHTML);
//        };
        //(function () { /* code */ } ()); // 推荐使用这个
        //(function () { /* code */ })(); // 但是这个也是可以用的
        /**
         * 下面两种写法都是可以的,因为它在自执行函数表达式闭包的内部
         * 因为闭包直接可以引用传入的这些参数,利用这些被lock住的传入参数,自执行函数表达式可以有效地保存状态。
         * i的值作为locked的索引存在,尽管循环执行以后,i的值变成了最后一个keybutton
         * 但闭包内部的lockedInIndex值是没有改变,因为他已经执行完毕了
         * 所以当点击连接的时候,结果是正确的
         */
        
//        (function(i){
//            keyButton[i].onclick = function() {
//            return calculate.showExpression(keyButton[i].innerHTML);
//            };
//        }(i));
        /**
         * 你也可以像下面这样应用,在处理函数那里使用自执行函数表达式
         * 但是相对来说,上面的代码更具可读性
         */
        keyButton[i].onclick = (function(index) {
            return function() {
                calculate.showExpression(keyButton[index].innerHTML);
            };
        })(i);
    }
};


#calculate {
    width: 300px;
    height: 320px;
    border: 1px #32CD32 solid ;
    border-radius: 5px;
    background-color: #00CCFF;
}
input {
    width: 97%;
    border-radius: 7px;
    background-color: #40e0d0;
    height: 8%;
    align-content: center;
    margin: 4px;
    text-align: right;
    font-size: 20px;
}
#keyboard {
   width: 100%;
    border-radius: 5px;
    height: 85%;
}
table {
    width: 100%;
    height: 100%;
}
tr td {
    width: 25%;
    height: 20%;
    background-color: #33CCFF;
    border: 1px solid;
    border-radius: 7px;
    text-align: center;
}
tr td:hover {
    background-color: #3366FF;
    cursor: pointer;
}
tr td:visited {
    background-color: #333399;
}


  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
持多位数输入和小数计算。可以使用栈来实现括号和嵌套计算器。 以下是一个简单的示例代码: ```c++ #include <iostream> #include <stack> #include <string> using namespace std; // 判断字符是否为数字 bool isDigit(char c) { return c >= '0' && c <= '9'; } // 将字符串转化为数字 double strToDouble(string str) { double res = 0.0; double base = 1.0; bool flag = false; // 是否有小数点 int i = 0; if (str[i] == '-') { flag = true; ++i; } for (; i < str.size(); ++i) { if (str[i] == '.') { flag = true; continue; } if (flag) { base *= 0.1; res += (str[i] - '0') * base; } else { res = res * 10 + (str[i] - '0'); } } return flag ? (flag && str[0] == '-' ? -res : res) : (flag && str[0] == '-' ? -res : res); } // 计算两个数的运算结果 double calculate(double a, double b, char op) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; default: return 0; } } // 计算表达式的值 double evaluate(string expr) { stack<double> nums; stack<char> ops; for (int i = 0; i < expr.size(); ++i) { if (isDigit(expr[i])) { // 数字 int j = i; while (j < expr.size() && (isDigit(expr[j]) || expr[j] == '.')) { ++j; } double num = strToDouble(expr.substr(i, j - i)); nums.push(num); i = j - 1; } else if (expr[i] == '(') { // 左括号 ops.push(expr[i]); } else if (expr[i] == ')') { // 右括号 while (ops.top() != '(') { double b = nums.top(); nums.pop(); double a = nums.top(); nums.pop(); char op = ops.top(); ops.pop(); nums.push(calculate(a, b, op)); } ops.pop(); } else if (expr[i] == '+' || expr[i] == '-') { // 加减 while (!ops.empty() && ops.top() != '(') { double b = nums.top(); nums.pop(); double a = nums.top(); nums.pop(); char op = ops.top(); ops.pop(); nums.push(calculate(a, b, op)); } ops.push(expr[i]); } else if (expr[i] == '*' || expr[i] == '/') { // 乘除 while (!ops.empty() && (ops.top() == '*' || ops.top() == '/')) { double b = nums.top(); nums.pop(); double a = nums.top(); nums.pop(); char op = ops.top(); ops.pop(); nums.push(calculate(a, b, op)); } ops.push(expr[i]); } } while (!ops.empty()) { double b = nums.top(); nums.pop(); double a = nums.top(); nums.pop(); char op = ops.top(); ops.pop(); nums.push(calculate(a, b, op)); } return nums.top(); } int main() { string expr; cout << "请输入表达式:" << endl; cin >> expr; double res = evaluate(expr); cout << "计算结果为:" << res << endl; return 0; } ``` 这个程序支持多位数输入和小数计算,可以通过栈来实现括号和嵌套计算器

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值