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 插件学习(二)
Aug 06 Javascript
jQuery实现自动调整字体大小的方法
Jun 15 Javascript
详解JavaScript中数组的相关知识
Jul 29 Javascript
jQuery动画显示和隐藏效果实例演示(附demo源码下载)
Dec 31 Javascript
限制复选框最多选择项的实现代码
May 30 Javascript
老生常谈 关于JavaScript的类的继承
Jun 24 Javascript
JavaScript实现页面无操作倒计时退出
Oct 22 Javascript
微信小程序 UI与容器组件总结
Feb 21 Javascript
jquery点赞功能实现代码 点个赞吧!
May 29 jQuery
lhgcalendar时间插件限制只能选择三个月的实现方法
Jul 03 Javascript
原生js实现的移动端可拖动进度条插件功能详解
Aug 15 Javascript
使用Vue3+Vant组件实现App搜索历史记录功能(示例代码)
Jun 09 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反射实际应用示例
2019/04/03 PHP
删除重复数据的算法
2006/11/23 Javascript
js动态切换图片的方法
2015/01/20 Javascript
AngularJS中的$watch(),$digest()和$apply()区分
2016/04/04 Javascript
Bootstrap模态框调用功能实现方法
2016/09/19 Javascript
jQuery ajaxForm()的应用
2016/10/14 Javascript
微信公众平台开发教程(四) 实例入门:机器人回复(附源码)
2016/12/02 Javascript
解析利用javascript如何判断一个数为素数
2016/12/08 Javascript
详解Vue 动态添加模板的几种方法
2017/04/25 Javascript
bootstrap插件treeview实现全选父节点下所有子节点和反选功能
2017/07/21 Javascript
JS正则表达式完美实现身份证校验功能
2017/10/18 Javascript
JavaScript模板引擎原理与用法详解
2018/12/24 Javascript
jQuery ajax仿Google自动提示SearchSuggess功能示例
2019/03/28 jQuery
vue element-ui实现动态面包屑导航
2019/12/23 Javascript
详解在IDEA中将Echarts引入web两种方式(使用js文件和maven的依赖导入)
2020/07/11 Javascript
详解Python函数可变参数定义及其参数传递方式
2017/08/02 Python
python实现批量修改文件名代码
2017/09/10 Python
Python快速查找list中相同部分的方法
2018/06/27 Python
Python3爬虫学习之应对网站反爬虫机制的方法分析
2018/12/12 Python
Python使用reportlab模块生成PDF格式的文档
2019/03/11 Python
Python多版本开发环境管理工具介绍
2019/07/03 Python
实例详解Python装饰器与闭包
2019/07/29 Python
IronPython连接MySQL的方法步骤
2019/12/27 Python
pycharm不能运行.py文件的解决方法
2020/02/12 Python
基于python的opencv图像处理实现对斑马线的检测示例
2020/11/29 Python
柒牌官方商城:中国男装优秀品牌
2017/06/30 全球购物
国际书籍零售商:Wordery
2017/11/01 全球购物
日本乐天官方海外转运服务:Rakuten Global Express
2018/11/30 全球购物
主治医师岗位职责
2013/12/10 职场文书
男方父母证婚词
2014/01/12 职场文书
商场促销活动方案
2014/02/08 职场文书
优秀小学生事迹材料
2014/12/26 职场文书
2015年小学远程教育工作总结
2015/07/28 职场文书
详解JS ES6编码规范
2021/05/07 Javascript
MySQL 语句执行顺序举例解析
2022/06/05 MySQL
Django框架中表单的用法
2022/06/10 Python