javascript 实现计算器效果(输入中缀表达式字符串=>转为后缀表达式数组=>后缀表达式计算)

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        *{margin: 0;padding: 0;user-select: none;}
        li{list-style: none;}
        .box{width: 250px;height: 500px;margin: 100px auto;}
        .show{width: 188px;height: 20px;border: 1px solid orange;margin: 2px;text-align: center;line-height: 20px;user-select: text;font-size: 14px;color: #ccc;font-weight: 600;padding: 15px;}
        li{width: 50px;height: 50px;border: 1px solid orange;margin: 2px;float: left;text-align: center;line-height: 50px;}
        button{width: 70px;height: 35px;margin: 10px;}
        .compute{margin-right: 5px;}
        .reset{margin-left: 5px;}
    </style>
</head>

<body>
    <div class="box">
        <div class="show"></div>
        <ul class="list">
            <li>1</li>
            <li>2</li>
            <li>3</li>
            <li>+</li>
            <li>4</li>
            <li>5</li>
            <li>6</li>
            <li>-</li>
            <li>7</li>
            <li>8</li>
            <li>9</li>
            <li>*</li>
            <li>(</li>
            <li>0</li>
            <li>)</li>
            <li>/</li>
            <li>.</li>
        </ul>
        <button class="compute">compute</button>
        <button class="reset">reset</button>
    </div>
</body>
<script>

    // 为每一个 li 绑定点击事件
    var liList = document.getElementsByTagName("li")
    var exstr = ""
    for (let i = 0; i < liList.length; i++) {
        let li = liList[i]
        li.onclick = function () {
            // 获取中缀表达式
            exstr += this.textContent
            show.innerHTML = exstr
            // console.log(exstr)
        }
    }

    // 点击计算按钮,在显示框中输出值
    var show = document.getElementsByClassName("show")[0]
    var combtn = document.getElementsByClassName("compute")[0]
    var rebtn = document.getElementsByClassName("reset")[0]

    combtn.onclick = function () {
        if(exstr){
            show.innerHTML = computeSuffix(midTransSuffix(strSplit(exstr)))
            exstr = ""
        }
    }

    rebtn.onclick = function () {
        show.innerHTML = "请输入计算式"
        exstr = ""
    }

    // 增加一个按 Enter 键 实现计算的事件
    document.onkeypress = function (evt) {
        // evt.key 获取按键的值(区分英文字母大小写)
        console.log(evt.key)
        if (evt.key == "Enter") {
            show.innerHTML = computeSuffix(midTransSuffix(strSplit(exstr)))
            exstr = ""
        } else {
            exstr += evt.key
            show.innerHTML = exstr
        }
        console.log(exstr, "exstr")
    }


    // ==================================================================================================

    //                                  将中缀表达式 字符串 => 数组

    // ==================================================================================================
    function strSplit(exstr) {
        // 声明变量存储操作数左下标 数组
        var index = 0, list = []

        for (var i = 0; i < exstr.length; i++) {
            // 忽略空格
            if (exstr[i] == " ") {
                continue
            }
            
            // 如果是操作符
            // 1. 先将操作符前的操作数加入到数组中(判断是否为空)
            // 2. 再将操作符本身加入到数组中
            if ("+-*/()".indexOf(exstr[i]) != -1) {
                if (exstr.slice(index, i)) {
                    list.push(exstr.slice(index, i))
                }
                list.push(exstr[i])
                // 3. 将左下标后移一位
                index = i + 1
            }
        }

        // 循环结束判断是否存在最后一位操作数,存在,加入数组
        if (i == exstr.length && exstr.slice(index, i)) {
            list.push(exstr.slice(index, i))
        }
        return list
    }



    // function strSplit(exstr) {
    //     // 将输入的中缀表达式转为数组
    //     var numsex = []
    //     // 左右指针 记录操作数的起始下标
    //     var left = 0, right = -1
    //     // 以操作符分隔
    //     for (var i = 0; i < exstr.length; i++) {

    //         // 忽略空格
    //         if (exstr[i] == " ") {
    //             continue
    //         }

    //         // 判断,是否输入了操作数和操作符外的其他字符
    //         if ("+-*/()1234567890.".indexOf(exstr[i]) == -1) {
    //             return []
    //         }

    //         if ("+-*/".indexOf(exstr[i]) != -1) {
    //             // 是操作符
    //             numsex.push(exstr.slice(left, i))
    //             numsex.push(exstr[i])
    //             left = i + 1
    //         }

    //         if (exstr[i] == "(") {
    //             numsex.push(exstr[i])
    //             left = i + 1
    //         }

    //         if (exstr[i] == ")") {
    //             numsex.push(exstr.slice(left, i))
    //             numsex.push(exstr[i])
    //             left = i + 1
    //         }

    //         if (i == exstr.length - 1 && exstr.slice(left, i + 1).length > 0) {
    //             // 将最后一个操作数加入到数组中
    //             numsex.push(exstr.slice(left, i + 1))
    //         }
    //     }
    //     console.log(numsex, "中缀数组")
    //     return numsex
    // }
    // console.log(strSplit("103-5"))


    // ==================================================================================================

    //                                  中缀表达式转后缀表达式

    // ==================================================================================================
    function midTransSuffix(exlist) {
        
        // 栈的创建
        var opStack = new Object()
        opStack.value = []
        opStack.push = function (item) {
            this.value.push(item)
        }
        opStack.pop = function () {
            return this.value.pop()
        }
        opStack.peek = function () {
            return this.value[this.value.length - 1]
        }
        opStack.isEmpty = function () {
            return this.value.length == 0
        }
        opStack.size = function () {
            return this.value.length
        }

        // 定义优先级判断
        var dic = {}
        dic['*'] = 3
        dic['/'] = 3
        dic['+'] = 2
        dic['-'] = 2
        dic['('] = 1

        // 列表存储转换的后缀表达式
        var outputList = []

        for (var i of exlist) {

            if ("+-*/()".indexOf(i) == -1) {
                // 是操作数,直接添加到 列表中
                outputList.push(i)

            } else if (i == "(") {
                opStack.push(i)
            } else if (i == ")") {
                while (opStack.peek() != "(") {
                    outputList.push(opStack.pop())
                }
                opStack.pop()
            } else {
                while (!opStack.isEmpty() && dic[opStack.peek()] >= dic[i]) {
                    outputList.push(opStack.pop())
                }
                opStack.push(i)
            }
        }

        while (!opStack.isEmpty() && opStack.peek() != "") {
            outputList.push(opStack.pop())
        }
        console.log(outputList, "后缀数组")
        return outputList
    }

    // var prefix = "a+b*c+(d*e+f)*g"

    // console.log(midTransSuffix(prefix))
    // 检验栈对象是否成功
    // console.log(opStack.value)
    // console.log(opStack.push(5))
    // console.log(opStack.value)
    // console.log(opStack.push(10))
    // console.log(opStack.peek())
    // console.log(opStack.isEmpty())
    // console.log(opStack.size())
    // console.log(opStack.value)



    // ==================================================================================================

    //                                  后缀表达式计算

    // ==================================================================================================
    function computeSuffix(exlist) {

        // 如果接收的是空数组
        // 代表表达式错误 / 用户未输入
        if (exlist.length == 0) {
            return "请输入正确的表达式"
        }

        // 栈的创建
        var opStack = new Object()
        opStack.value = []
        opStack.push = function (item) {
            this.value.push(item)
        }
        opStack.pop = function () {
            return this.value.pop()
        }
        opStack.peek = function () {
            return this.value[this.value.length - 1]
        }
        opStack.isEmpty = function () {
            return this.value.length == 0
        }
        opStack.size = function () {
            return this.value.length
        }

        computeCharString = "+-*/"
        
        for (var i = 0; i < exlist.length; i++) {
            // 遍历表达式
            switch (exlist[i]) {
                case "+":
                    opStack.push(opStack.pop() + opStack.pop())
                    break
                case "-":
                    var jianshu = opStack.pop()
                    opStack.push(opStack.pop() - jianshu)
                    break
                case "*":
                    opStack.push(opStack.pop() * opStack.pop())
                    break
                case "/":
                    var chushu = opStack.pop()
                    opStack.push(opStack.pop() / chushu)
                    break
                default:
                    opStack.push(parseFloat(exlist[i]))
            }
        }
        // return Math.round(opStack.pop(), 2)
        var result = opStack.pop()
        console.log(result, "后缀结果")
        if (isNaN(result)) {
            return "计算出错啦!"
        }
        return result % 1 == 0 ? result : result.toFixed(2)
    }

    // console.log(computeSuffix(["4", "2", "/"]))
    // var test = "12+6-(3+1)"
    // console.log(computeSuffix(midTransSuffix(strSplit(test))))



</script>

</html>

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值