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 相关文章推荐
Javascript &amp; DHTML 实例编程(教程)基础知识
Jun 02 Javascript
javascript窗口宽高,鼠标位置,滚动高度(详细解析)
Nov 18 Javascript
html文本框提示效果的示例代码
Jun 28 Javascript
PHP中CURL的几个经典应用实例
Jan 23 Javascript
jsp 网站引入外部css或者js失效问题解决
Oct 31 Javascript
AngularJS实现Input格式化的方法
Nov 07 Javascript
解决Angular.Js与Django标签冲突的方案
Dec 20 Javascript
EasyUI学习之Combobox下拉列表(1)
Dec 29 Javascript
vue绑定class与行间样式style详解
Aug 16 Javascript
vscode配置vue下的es6规范自动格式化详解
Mar 20 Javascript
前端使用crypto.js进行加密的函数代码
Aug 16 Javascript
JS实现纸牌发牌动画
Jan 19 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
解决163/sohu/sina不能够收到PHP MAIL函数发出邮件的问题
2009/03/13 PHP
php打包压缩文件之ZipArchive方法用法分析
2016/04/30 PHP
PHP实现递归目录的5种方法
2016/10/27 PHP
老生常谈php中传统验证与thinkphp框架(必看篇)
2017/06/10 PHP
JavaScript 实现模态对话框 源代码大全
2009/05/02 Javascript
Jquery选择子控件&quot;大于号&quot;和&quot; &quot;区别介绍及使用示例
2013/06/25 Javascript
可插入图片的TEXT文本框
2013/12/27 Javascript
easyui Draggable组件实现拖动效果
2015/08/19 Javascript
快速掌握Node.js中setTimeout和setInterval的使用方法
2016/03/21 Javascript
Web打印解决方案之普通报表打印功能
2016/08/29 Javascript
微信小程序 Toast自定义实例详解
2017/01/20 Javascript
js+html5实现页面可刷新的倒计时效果
2017/07/15 Javascript
2种在vue项目中使用百度地图的简单方法
2018/09/28 Javascript
小程序转发探索示例
2019/02/19 Javascript
vue 获取及修改store.js里的公共变量实例
2019/11/06 Javascript
Python实现从url中提取域名的几种方法
2014/09/26 Python
对python中执行DOS命令的3种方法总结
2018/05/12 Python
分享vim python缩进等一些配置
2018/07/02 Python
Python中断多重循环的思路总结
2019/10/04 Python
如何通过Python3和ssl实现加密通信功能
2020/05/09 Python
利用SVG和CSS3来实现一个炫酷的边框动画
2015/07/22 HTML / CSS
html5触摸事件判断滑动方向的实现
2018/06/05 HTML / CSS
超级英雄、电影和电视、乐队和音乐T恤:Loud Clothing
2019/09/01 全球购物
好的自荐信包括什么内容
2013/11/07 职场文书
优秀交警事迹材料
2014/01/26 职场文书
烹调加工管理制度
2014/02/04 职场文书
2014县政府领导班子对照检查材料思想汇报
2014/09/25 职场文书
给老婆的保证书怎么写
2015/05/08 职场文书
升学宴家长致辞
2015/07/27 职场文书
给学校的建议书400字
2015/09/14 职场文书
公司员工违法违章行为检讨书
2019/06/24 职场文书
会议承办单位欢迎词
2019/07/09 职场文书
Python 把两层列表展开平铺成一层(5种实现方式)
2021/04/07 Python
详解MySQL集群搭建
2021/05/26 MySQL
springboot+WebMagic+MyBatis爬虫框架的使用
2021/08/07 Java/Android
Redis 哨兵机制及配置实现
2022/03/25 Redis