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字符串插入、删除、替换函数使用示例
Jul 25 Javascript
JS实现根据当前文字选择返回被选中的文字
May 21 Javascript
jquery模拟实现鼠标指针停止运动事件
Jan 12 Javascript
浅谈js中的延迟执行和定时执行
May 31 Javascript
JavaScript中 ES6 generator数据类型详解
Aug 11 Javascript
无阻塞加载js,防止因js加载不了影响页面显示的问题
Dec 18 Javascript
Web开发中客户端的跳转与服务器端的跳转的区别
Mar 05 Javascript
基于jQuery实现文字打印动态效果
Apr 21 jQuery
JavaScript实现选中文字提示新浪微博分享效果
Jun 15 Javascript
jQuery实现下拉菜单的实例代码
Jun 19 jQuery
ES6中Symbol、Set和Map用法详解
Aug 20 Javascript
Emberjs 通过 axios 下载文件的方法
Sep 03 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
解析PHP提交后跳转
2013/06/23 PHP
php中socket的用法详解
2014/10/24 PHP
MacOS 安装 PHP的图片裁剪扩展Tclip
2015/03/25 PHP
JavaScript中的History历史对象
2008/01/16 Javascript
jQuery用unbind方法去掉hover事件及其他方法介绍
2013/03/18 Javascript
jQuery基于muipicker实现仿ios时间选择
2016/02/22 Javascript
Javascript 创建类并动态添加属性及方法的简单实现
2016/10/20 Javascript
快速掌握jQuery插件开发
2017/01/19 Javascript
Vue之Watcher源码解析(2)
2017/07/19 Javascript
js设置鼠标悬停改变背景色实现详解
2019/06/26 Javascript
vue通过过滤器实现数据格式化
2020/07/20 Javascript
python使用arp欺骗伪造网关的方法
2015/04/24 Python
Python对list列表结构中的值进行去重的方法总结
2016/05/07 Python
基于python时间处理方法(详解)
2017/08/14 Python
通过Py2exe将自己的python程序打包成.exe/.app的方法
2018/05/26 Python
Django项目中model的数据处理以及页面交互方法
2018/05/30 Python
Python数据抓取爬虫代理防封IP方法
2018/12/23 Python
python实现生成字符串大小写字母和数字的各种组合
2019/01/01 Python
简单了解python代码优化小技巧
2019/07/08 Python
python或C++读取指定文件夹下的所有图片
2019/08/31 Python
如何基于python实现画不同品种的樱花树
2020/01/03 Python
keras中的卷积层&amp;池化层的用法
2020/05/22 Python
Pycharm配置autopep8实现流程解析
2020/11/28 Python
html5 横向滑动导航栏的方法示例
2020/05/08 HTML / CSS
Fossil加拿大官网:化石手表、手袋、首饰及配饰
2019/04/23 全球购物
实习生个人的自我评价
2013/12/08 职场文书
大学生求职信范文应怎么写
2014/01/01 职场文书
大学生饮食配送创业计划书
2014/01/04 职场文书
计算机网络工程专业职业生涯规划书
2014/03/10 职场文书
班级文化建设标语
2014/06/23 职场文书
上班迟到检讨书范文300字
2014/11/02 职场文书
2014年护士工作总结范文
2014/11/11 职场文书
校长师德表现自我评价
2015/03/04 职场文书
2015中秋节晚会开场白
2015/07/30 职场文书
团结主题班会
2015/08/13 职场文书
swagger如何返回map字段注释
2021/07/03 Java/Android