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 相关文章推荐
date.parse在IE和FF中的区别
Jul 29 Javascript
javascript实现网页屏蔽Backspace事件,输入框不屏蔽
Jul 21 Javascript
JavaScript+html5 canvas制作色彩斑斓的正方形效果
Jan 27 Javascript
微信小程序  action-sheet详解及实例代码
Nov 09 Javascript
基于JavaScript实现复选框的全选和取消全选
Feb 09 Javascript
脚本div实现拖放功能(两种)
Feb 13 Javascript
Angularjs在360兼容模式下取数据缓存问题的解决办法
Jun 22 Javascript
js实现图片上传预览原理分析
Jul 13 Javascript
Bootstrap Table 删除和批量删除
Sep 22 Javascript
详细分析JS函数去抖和节流
Dec 05 Javascript
ionic grid(栅格)九宫格制作详解
Jun 30 Javascript
JavaScript生成随机验证码代码实例
Sep 28 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 array_pop()数组函数将数组最后一个单元弹出(出栈)
2011/07/12 PHP
用PHP实现的四则运算表达式计算实现代码
2011/08/02 PHP
简单概括PHP的字符串中单引号与双引号的区别
2016/05/07 PHP
PHP树-不需要递归的实现方法
2016/06/21 PHP
深入理解PHP中mt_rand()随机数的安全
2017/10/12 PHP
js获取单元格自定义属性值的代码(IE/Firefox)
2010/04/05 Javascript
javascript跨域的4种方法和原理详解
2014/04/08 Javascript
jQuery模拟select实现下拉菜单功能
2016/06/20 Javascript
jQuery+CSS实现简单切换菜单示例
2016/07/27 Javascript
关于动态执行代码(js的Eval)实例详解
2016/08/15 Javascript
浅谈angular懒加载的一些坑
2016/08/20 Javascript
jQuery实现限制文本框的输入长度
2017/01/11 Javascript
jQuery使用方法
2017/02/04 Javascript
Angular使用 ng-img-max 调整浏览器中的图片的示例代码
2017/08/17 Javascript
详解使用Vue Router导航钩子与Vuex来实现后退状态保存
2017/09/11 Javascript
vue-cli构建项目使用 less的方法
2017/10/04 Javascript
小程序外卖订单界面的示例代码
2019/12/30 Javascript
Vue切换Tab动态渲染组件的操作
2020/09/21 Javascript
python访问类中docstring注释的实现方法
2015/05/04 Python
深入浅析ImageMagick命令执行漏洞
2016/10/11 Python
Python利用multiprocessing实现最简单的分布式作业调度系统实例
2017/11/14 Python
python re模块的高级用法详解
2018/06/06 Python
Python实现将数据写入netCDF4中的方法示例
2018/08/30 Python
python文本数据处理学习笔记详解
2019/06/17 Python
python 杀死自身进程的实现方法
2019/07/01 Python
Python requests模块基础使用方法实例及高级应用(自动登陆,抓取网页源码)实例详解
2020/02/14 Python
postman和python mock测试过程图解
2020/02/22 Python
详解如何使用Pytest进行自动化测试
2021/01/14 Python
css3实现背景动态渐变效果
2019/12/10 HTML / CSS
领先的荷兰线上超市:荷兰之家Holland at Home(支持中文)
2021/01/21 全球购物
技术总监的工作职责
2013/11/13 职场文书
《理想》教学反思
2014/02/17 职场文书
2014年幼儿园保育工作总结
2014/12/02 职场文书
办公室主任岗位职责范本
2015/03/31 职场文书
2015年计算机教师工作总结
2015/07/22 职场文书
2016年小学推普宣传周活动总结
2016/04/06 职场文书