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 相关文章推荐
ExtJS GridPanel 根据条件改变字体颜色
Mar 08 Javascript
js实现模拟计算器退格键删除文字效果的方法
May 07 Javascript
Javascript将JSON日期格式化
Aug 23 Javascript
基于javascript实现的快速排序
Dec 02 Javascript
javascript 组合按键事件监听实现代码
Feb 21 Javascript
详解vue-cli + webpack 多页面实例应用
Apr 25 Javascript
JavaScript中undefined和null的区别
May 03 Javascript
移动端效果之IndexList详解
Oct 20 Javascript
利用nginx + node在阿里云部署https的步骤详解
Dec 19 Javascript
Vue-cli3项目配置Vue.config.js实战记录
Jul 29 Javascript
微信小程序实现自动定位功能
Oct 31 Javascript
react使用antd的上传组件实现文件表单一起提交功能(完整代码)
Jun 29 Javascript
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
[FAQ]PHP中的一些常识:类篇
2006/10/09 PHP
实现“上一页”和“下一页按钮
2006/10/09 PHP
基于HTTP长连接的&quot;服务器推&quot;技术的php 简易聊天室
2009/10/31 PHP
PHP时间格式控制符对照表分享
2013/07/23 PHP
PHP实现通过文本文件统计页面访问量功能示例
2019/02/13 PHP
读jQuery之九 一些瑕疵说明
2011/06/21 Javascript
jquery的相对父元素和相对文档定位示例代码
2013/08/02 Javascript
js编写trim()函数及正则表达式的运用
2013/10/24 Javascript
JavaScript模块规范之AMD规范和CMD规范
2015/10/27 Javascript
每天一篇javascript学习小结(Date对象)
2015/11/13 Javascript
Javascript如何判断数据类型和数组类型
2016/06/22 Javascript
微信小程序之ES6与事项助手的功能实现
2016/11/30 Javascript
微信公众号 摇一摇周边功能开发
2016/12/08 Javascript
微信小程序 实战实例开发流程详细介绍
2017/01/05 Javascript
AngularJS实现使用路由切换视图的方法
2017/01/24 Javascript
基于vue2.0实现简单轮播图
2017/11/27 Javascript
vue 监听键盘回车事件详解 @keyup.enter || @keyup.enter.native
2018/08/25 Javascript
vue 使某个组件不被 keep-alive 缓存的方法
2018/09/21 Javascript
微信小程序wx.navigateTo中events属性实现页面间通信传值,数据同步
2019/07/13 Javascript
详解vue beforeEach 死循环问题解决方法
2020/02/25 Javascript
JS 设计模式之:单例模式定义与实现方法浅析
2020/05/06 Javascript
[54:24]Optic vs TNC 2018国际邀请赛小组赛BO2 第二场
2018/08/18 DOTA
[01:36:17]DOTA2-DPC中国联赛 正赛 Ehome vs iG BO3 第一场 1月31日
2021/03/11 DOTA
django中send_mail功能实现详解
2018/02/06 Python
python中数据爬虫requests库使用方法详解
2018/02/11 Python
python 实现批量xls文件转csv文件的方法
2018/10/23 Python
Python : turtle色彩控制实例详解
2020/01/19 Python
Pytorch环境搭建与基本语法
2020/06/03 Python
python爬虫---requests库的用法详解
2020/09/28 Python
一款纯css3实现的颜色渐变按钮的代码教程
2014/11/12 HTML / CSS
应届生自我鉴定
2013/12/11 职场文书
人力资源管理毕业生自荐信
2014/06/26 职场文书
幼儿园中秋节活动总结
2015/03/23 职场文书
写给同事的离职感言
2015/08/04 职场文书
Apache压力测试工具的安装使用
2021/03/31 Servers
vue完美实现el-table列宽自适应
2021/05/08 Vue.js