javascript中解析四则运算表达式的算法和示例


Posted in Javascript onAugust 11, 2014

在编写代码时我们有时候会碰到需要自己解析四则运算表达式的情况,本文简单的介绍使用JavaScript实现对简单四则运算表达式的解析。

一、熟悉概念

中缀表示法(或中缀记法)是一个通用的算术或逻辑公式表示方法, 操作符是以中缀形式处于操作数的中间(例:3 + 4)。也就是我们最常用的算术表达式,中缀表达式对于人类来说比较容易理解,但是不易于计算机解析。

逆波兰表示法(Reverse Polish notation,RPN,或逆波兰记法),是一种是由波兰数学家扬·武卡谢维奇1920年引入的数学表达式方式,在逆波兰记法中,所有操作符置于操作数的后面,因此也被称为后缀表示法。逆波兰记法不需要括号来标识操作符的优先级。逆波兰表示法容易使用堆栈结构对表达式进行解析并计算,所以,这里我们解析四则元素表达式,是先从中缀表达式,转换为逆波兰表达式。然后再计算值。

二、转换流程

中缀表达式转换为后缀表达式(调度场算法)

1.输入队列弹出一个记号
2.如果记号为数字,添加到输出队列中
3.如果是一个操作符(+-*/)则比较它与输出堆栈中栈顶的操作符,如果优先级小于或等于栈顶的操作符,那么将栈顶的操作符弹出并加入输出队列(循环,直到上述条件不满足),最后将本次的操作符压入堆栈。
4.如果是一个左括号,压入堆栈
5.如果是一个右括号,从栈中不断的弹出操作符,并加入输出队列,知道栈顶的元素为左括号。弹出左括号,不加入输出队列。如果没有发现左括号,说明原来的表达式中括号不对称,有错误。
6.如果输入队列为空,而栈中尚有操作符时,如果栈顶的操作符为左括号,则说明原表达式有不匹配的括号。将栈中的操作符逐个弹出,加入输出队列。
7.完成

javascript中解析四则运算表达式的算法和示例

三、转换代码实现

function isOperator(value){
	var operatorString = "+-*/()";
	return operatorString.indexOf(value) > -1
}

function getPrioraty(value){
	switch(value){
		case '+':
		case '-':
			return 1;
		case '*':
		case '/':
			return 2;
		default:
			return 0;
	}
}

function prioraty(o1, o2){
	return getPrioraty(o1) <= getPrioraty(o2);
}

function dal2Rpn(exp){
	var inputStack = [];
	var outputStack = [];
	var outputQueue = [];

	for(var i = 0, len = exp.length; i < len; i++){
		var cur = exp[i];
		if(cur != ' ' ){
			inputStack.push(cur);
		}
	}
	console.log('step one');
	while(inputStack.length > 0){
		var cur = inputStack.shift();
		if(isOperator(cur)){
			if(cur == '('){
				outputStack.push(cur);
			}else if(cur == ')'){
				var po = outputStack.pop();
				while(po != '(' && outputStack.length > 0){
					outputQueue.push(po);
					po = outputStack.pop();
				}
				if(po != '('){
					throw "error: unmatched ()";
				}
			}else{
				while(prioraty(cur, outputStack[outputStack.length - 1]) && outputStack.length > 0){
					outputQueue.push(outputStack.pop());
				}
				outputStack.push(cur);
			}
		}else{
			outputQueue.push(new Number(cur));
		}
	}
	console.log('step two');
	if(outputStack.length > 0){
		if(outputStack[outputStack.length - 1] == ')' || outputStack[outputStack.length - 1] == '('){
			throw "error: unmatched ()";
		}
		while(outputStack.length > 0){
			outputQueue.push(outputStack.pop());
		}
	}
	console.log('step three');
	return outputQueue;

}

console.log(dal2Rpn('1 + 2'));
console.log(dal2Rpn('1 + 2 + 3'));
console.log(dal2Rpn('1 + 2 * 3'));
console.log(dal2Rpn('1 + 2 * 3 - 4 / 5'));
console.log(dal2Rpn('( 1 + 2 )'));

console.log(dal2Rpn('( 1 + 2 ) * ( 3 - 4 ) / 5'));
console.log(dal2Rpn('( 1 + 2 ) * (( 3 - 4 ) / 5)'));

四、逆波兰表达式求值

1.从输入队列中弹出一个记号
2.如果是操作数,加入输出堆栈
3.如果是一个操作符,从输出堆栈中弹出两个操作数并进行计算,并将计算得到的值压入输出堆栈。
4.循环操作,如果输入队列为空,且输出堆栈只有一个数则这个数为结果,否则是出现了多余的操作数。

五、计算代码

function evalRpn(rpnQueue){
	var outputStack = [];
	while(rpnQueue.length > 0){
		var cur = rpnQueue.shift();

		if(!isOperator(cur)){
			outputStack.push(cur);
		}else{
			if(outputStack.length < 2){
				throw "unvalid stack length";
			}
			var sec = outputStack.pop();
			var fir = outputStack.pop();

			outputStack.push(getResult(fir, sec, cur));
		}
	}

	if(outputStack.length != 1){
		throw "unvalid expression";
	}else{
		return outputStack[0];
	}
}

六、结语

逆波兰表示法,在初次接触的时候感觉不太习惯,但是熟悉之后,会发现,其实思路特别简单,不像中缀表示法,还有各种优先级啊,还有小括号之类的,逻辑特别麻烦,还是逆波兰表示法比较简洁,完全不用考虑优先级,也没用小括号,中括号还有大括号搅局。

Javascript 相关文章推荐
JQuery 前台切换网站的样式实现
Jun 22 Javascript
JQuery 写的个性导航菜单
Dec 24 Javascript
jquery获取被勾选的checked(选中)的那一行的3列和4列的值
Jul 04 Javascript
JavaScript创建对象的写法
Aug 29 Javascript
javascript初学者常用技巧
Sep 02 Javascript
JavaScript获取各大浏览器信息图示
Nov 20 Javascript
jQuery异步提交表单的两种方式
Sep 13 Javascript
用JavaScript和jQuery实现瀑布流
Mar 19 Javascript
基于模板引擎Jade的应用(详解)
Dec 12 Javascript
JS基于for语句编写的九九乘法表示例
Jan 04 Javascript
Vue实现todolist删除功能
Jun 26 Javascript
三种方式清除vue路由跳转router-link的历史记录
Apr 10 Vue.js
javascript实现的平方米、亩、公顷单位换算小程序
Aug 11 #Javascript
jquery访问ashx文件示例代码
Aug 11 #Javascript
jQuery实现的一个tab切换效果内部还嵌有切换
Aug 10 #Javascript
JavaScript动态改变HTML页面元素例如添加或删除
Aug 10 #Javascript
网页运行时提示对象不支持abigimage属性或方法
Aug 10 #Javascript
js中直接声明一个对象的方法
Aug 10 #Javascript
点击标签切换和自动切换DIV选项卡
Aug 10 #Javascript
You might like
php注入实例
2006/10/09 PHP
Laravel使用Caching缓存数据减轻数据库查询压力的方法
2016/03/15 PHP
PHP实现的文件浏览器功能简单示例
2019/09/12 PHP
jquery $.ajax各个事件执行顺序
2010/10/15 Javascript
DOM和XMLHttpRequest对象的属性和方法整理
2012/01/04 Javascript
禁止按回车键提交表单的方法
2015/06/11 Javascript
浅谈JS原型对象和原型链
2016/03/02 Javascript
分享JS数组求和与求最大值的方法
2016/08/11 Javascript
完美解决jQuery的hover事件在IE中不停闪动的问题
2017/02/10 Javascript
浅谈Angular6的服务和依赖注入
2018/06/27 Javascript
Vue常用的几个指令附完整案例
2018/11/06 Javascript
使用Node.js写一个代码生成器的方法步骤
2019/05/10 Javascript
vue-cli+iview项目打包上线之后图标不显示问题及解决方法
2019/10/16 Javascript
vue单应用在ios系统中实现微信分享功能操作
2020/09/07 Javascript
[58:46]OG vs NAVI 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/17 DOTA
[01:14:30]TNC vs VG 2019国际邀请赛淘汰赛 胜者组赛BO3 第二场 8.20.mp4
2019/08/22 DOTA
[55:45]LGD vs OG 2019国际邀请赛淘汰赛 胜者组 BO3 第三场 8.24
2019/09/10 DOTA
[01:20]PWL S2开团时刻第三期——团战可以输 蝙蝠必须死
2020/11/26 DOTA
python查看zip包中文件及大小的方法
2015/07/09 Python
python urllib urlopen()对象方法/代理的补充说明
2017/06/29 Python
python smtplib模块自动收发邮件功能(二)
2018/05/22 Python
Python批量生成幻影坦克图片实例代码
2019/06/04 Python
Python实现时间序列可视化的方法
2019/08/06 Python
Python爬虫运用正则表达式的方法和优缺点
2019/08/25 Python
python网络编程之五子棋游戏
2020/05/14 Python
Python结合百度语音识别实现实时翻译软件的实现
2021/01/18 Python
详解H5 活动页之移动端 REM 布局适配方法
2017/12/07 HTML / CSS
Pretty Little Thing爱尔兰:时尚女性服饰
2017/03/27 全球购物
大学生涯自我鉴定
2014/01/16 职场文书
道德之星事迹材料
2014/05/03 职场文书
汉语专业毕业生自荐信
2014/07/06 职场文书
党的群众路线教育实践活动个人剖析材料
2014/10/07 职场文书
表扬稿范文
2015/01/17 职场文书
原来实习报告是这样写的呀!
2019/07/03 职场文书
MySQL 8.0 之不可见列的基本操作
2021/05/20 MySQL
SpringBoot生成License的实现示例
2021/06/16 Java/Android