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 相关文章推荐
获取HTML DOM节点元素的方法的总结
Aug 21 Javascript
JavaScript OOP面向对象介绍
Dec 02 Javascript
jQuery的context属性用法实例
Dec 27 Javascript
javascript动态修改Li节点值的方法
Jan 20 Javascript
JS实现可拖曳、可关闭的弹窗效果
Sep 26 Javascript
jQuery EasyUI右键菜单实现关闭标签/选项卡
Oct 10 Javascript
JQueryEasyUI之DataGrid数据显示
Nov 23 Javascript
javascript基础知识讲解
Jan 11 Javascript
Javascript中的getter和setter初识
Aug 17 Javascript
原生js中ajax访问的实例详解
Sep 19 Javascript
移动端H5页面返回并刷新页面(BFcache)的方法
Nov 06 Javascript
微信小程序实现一个简单swiper代码实例
Dec 30 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根据指定位置和长度获得子字符串的方法
2015/03/17 PHP
php防止sql注入简单分析
2015/03/18 PHP
分享五个PHP7性能优化提升技巧
2015/12/07 PHP
又拍云异步上传实例教程详解
2016/04/19 PHP
PhpStorm2020 + phpstudyV8 +XDebug的教程详解
2020/09/17 PHP
js中将URL中的参数提取出来作为对象的实现代码
2011/08/16 Javascript
js自定义鼠标右键的实现原理及源码
2014/06/23 Javascript
javascript时间函数大全
2014/06/30 Javascript
jquery实现保存已选用户
2014/07/21 Javascript
JavaScript实现的链表数据结构实例
2015/04/02 Javascript
js实现刷新iframe的方法汇总
2015/04/27 Javascript
Js数组排序函数sort()介绍
2015/06/08 Javascript
Highcharts入门之简介
2016/08/02 Javascript
深入学习js瀑布流布局
2016/10/14 Javascript
nodejs入门教程五:连接数据库的方法分析
2017/04/24 NodeJs
简易Vue评论框架的实现(父组件的实现)
2018/01/08 Javascript
[01:09:19]DOTA2-DPC中国联赛 正赛 VG vs Aster BO3 第二场 2月28日
2021/03/11 DOTA
python实现定时同步本机与北京时间的方法
2015/03/24 Python
详解Python中的装饰器、闭包和functools的教程
2015/04/02 Python
Python tkinter模块中类继承的三种方式分析
2017/08/08 Python
利用python打印出菱形、三角形以及矩形的方法实例
2017/08/08 Python
Python使用xlwt模块操作Excel的方法详解
2018/03/27 Python
Python基于FTP模块实现ftp文件上传操作示例
2018/04/23 Python
浅谈Python3中strip()、lstrip()、rstrip()用法详解
2019/04/29 Python
对pyqt5多线程正确的开启姿势详解
2019/06/14 Python
Pycharm使用之设置代码字体大小和颜色主题的教程
2019/07/12 Python
pytorch: Parameter 的数据结构实例
2019/12/31 Python
tensorflow多维张量计算实例
2020/02/11 Python
优秀生推荐信范文
2013/11/28 职场文书
搞笑创意广告语
2014/03/17 职场文书
任命书格式
2014/06/05 职场文书
2014领导班子“四风问题”对照检查材料思想汇报(执法局)
2014/09/21 职场文书
实习报告范文
2019/07/30 职场文书
Nginx访问日志及错误日志参数说明
2021/03/31 Servers
JavaScript 定时器详情
2021/11/11 Javascript
在 Python 中利用 Pool 进行多线程
2022/04/24 Python