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 相关文章推荐
js中的window.open返回object的错误的解决方法
Aug 15 Javascript
window.location.reload()方法刷新页面弹出要再次显示该网页对话框
Apr 24 Javascript
Jquery仿IGoogle实现可拖动窗口示例代码
Aug 22 Javascript
javascript使用for循环批量注册的事件不能正确获取索引值的解决方法
Dec 20 Javascript
省市区三级联动下拉框菜单javascript版
Aug 11 Javascript
javascript简单比较日期大小的方法
Jan 05 Javascript
整理JavaScript对DOM中各种类型的元素的常用操作
May 05 Javascript
JQuery异步提交表单与文件上传功能示例
Jan 12 Javascript
js实现拖拽功能
Mar 01 Javascript
jQuery 循环遍历改变a标签的href(实例讲解)
Jul 12 jQuery
angularjs实现猜大小功能
Oct 23 Javascript
前端必备插件之纯原生JS的瀑布流插件Macy.js
Nov 22 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缩小png图片不损失透明色的解决方法
2013/12/25 PHP
PHP 中使用explode()函数切割字符串为数组的示例
2017/05/06 PHP
PHP实现防盗链的方法分析
2017/07/25 PHP
浅析PHP数据导出知识点
2018/02/17 PHP
如何用js控制css中的float的代码
2007/08/16 Javascript
web开发人员学习jQuery的6大理由及jQuery的优势介绍
2013/01/03 Javascript
用JavaScript修改CSS属性的代码
2013/05/06 Javascript
jquery实现标签支持图文排列带上下箭头按钮的选项卡
2015/03/14 Javascript
jQuery的几个我们必须了解的特点
2015/05/03 Javascript
js编写贪吃蛇的小游戏
2020/08/24 Javascript
JavaScript与jQuery实现的闪烁输入效果
2016/02/18 Javascript
全面了解JS中的匿名函数
2016/06/29 Javascript
浅谈js内置对象Math的属性和方法(推荐)
2016/09/19 Javascript
Reactjs实现通用分页组件的实例代码
2017/01/19 Javascript
seajs中最常用的7个功能、配置示例
2017/10/10 Javascript
详解Vue中watch的详细用法
2018/11/28 Javascript
在 Angular-cli 中使用 simple-mock 实现前端开发 API Mock 接口数据模拟功能的方法
2018/11/28 Javascript
Vue+Koa2 打包后进行线上部署的教程详解
2019/07/31 Javascript
Node.js 在本地生成日志文件的方法
2020/02/07 Javascript
Python的标准模块包json详解
2017/03/13 Python
matplotlib 纵坐标轴显示数据值的实例
2018/05/25 Python
python从list列表中选出一个数和其对应的坐标方法
2019/07/20 Python
pytorch索引查找 index_select的例子
2019/08/18 Python
Python模块/包/库安装的六种方法及区别
2020/02/24 Python
Selenium Webdriver元素定位的八种常用方式(小结)
2021/01/13 Python
欧迪办公美国官网:Office Depot
2016/08/22 全球购物
英国经典球衣网站:Classic Football Shirts
2017/05/20 全球购物
说出数据连接池的工作机制是什么?
2013/04/19 面试题
师范生教师实习自我鉴定
2013/09/27 职场文书
注塑工厂厂长岗位职责
2013/12/02 职场文书
党校培训自我鉴定
2014/02/01 职场文书
班级体育活动总结
2014/07/05 职场文书
整顿机关作风心得体会
2014/09/10 职场文书
收入证明范本
2015/06/12 职场文书
浅谈pytorch中stack和cat的及to_tensor的坑
2021/05/20 Python
前端JS获取URL参数的4种方法总结
2022/04/05 Javascript