1.原理
- 构建图形界面,实现数字按钮,和运算符号(+,-,/,*,=)
- 算式的显示界面可以设置为一个文本框,文本框的设置readonly
- 在点击了相应的按钮后,value的值执行字符串拼接,最后=使用eval函数
2.重构eval函数实现字符串运算
参考网址:波兰表达式 http://blog.haoji.me/postfix-notation.html
例:str = ‘2+(5+2(5+2))+510’
一般按照我们运算习惯都是先运算括号里面,但是怎么让机器知道这些呢
目标 [5,2,+] => 5+2
分析:这个是最里面的一层表达式,如果要实现这样的效果,那么下一步应该是
[5,2,2,+,] = 5+22
将5+2的结果再入栈操作,这里就直接可以看做是从左到右的执行顺序了
第一步:先将符号的运算确定好
规则:
- 建立一个栈,然后从左至右的遍历中缀表达式;
- 碰到数字直接输出,碰到操作符则需要进行优先级的比较,如果栈为空或者栈顶的操作符的优先级比当前的低,则将当前的操作符Push入栈,如果栈顶操作符的优先级大于等于当前的操作符,则POP栈顶操作符并输出,直到出现前一种情况为止;
括号需要特殊处理,如果是
(则直接入栈,如果是),则需要等到找到对应的(为止,并且当两者同时出现时则同时删除。// demo '2+(5+2*(5+2))+5*10'function houzhui(str) {//这里使用 /(\d*)/ 可以匹配并记住数字,并且在没有数字的时候匹配空let input = str.split(/(\d*)/), output = [], temp = []; // output表示输出,temp表示临时存放操作符的堆栈input = input.filter( value => value !== ''); // 清除空格let yxj = {'+': 1, '-': 1, '*': 2, '/': 2}; // 优先级input.forEach(current => {if(/\d/g.test(current)){output.push(current); // 如果是数字,直接放入输出栈}else if(current === '('){temp.push(current); // 如果左括号,放入堆栈}else if(current === ')') { // 如果是右括号,循环输出,直至匹配到左括号才停止while(temp.length > 0) {let op = temp.pop();if(op === '(') break;output.push(op);}} else { // 否则,如果是加减乘除,需要针对优先级做不同处理while(temp.length >= 0) {let op = temp[temp.length-1];// 如果堆栈为空,或者上一个操作符是(,或者当前操作符优先级比栈顶操作符优先级要高if(!temp.length || op === '(' || yxj[current] > yxj[op]) {temp.push(current);break;} else output.push(temp.pop());}}});// 输入循环结束后,如果操作符堆栈不为空,还要循环输出while(temp.length > 0) output.push(temp.pop());return output;}
第二步:调用函数,将每一个结果重新入栈
function countHouzhui(input) {let output = [];input.forEach(item => {if(/\d/g.test(item)) output.push(item);else {let n2 = output.pop();let n1 = output.pop();output.push(count(n1, n2, item));}});function count(n1, n2, op) {[n1,n2] = [n1,n2].map(Number);// 使用状态模式节约开销let state = {'*' :function (left,right) {return left * right;},'/' :function (left,right) {return left / right;},'%' :function (left,right) {return left % right;},'+' :function (left,right) {return left + right;},'-' :function (left,right) {return left - right;},};console.log(n1, n2, op);return state[op](n1, n2)}return output[0];}console.log(countHouzhui(houzhui('2+(5+2*(5+2))+5*10'))); // 输出 71
