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 相关文章推荐
Jquery升级新版本后选择器的语法问题
Jun 02 Javascript
js图片自动轮播代码分享(js图片轮播)
May 06 Javascript
详解JavaScript对象和数组
Dec 03 Javascript
微信jssdk在iframe页面失效问题的解决措施
Mar 03 Javascript
微信小程序 wxapp画布 canvas详细介绍
Oct 31 Javascript
JS实现移动端按首字母检索城市列表附源码下载
Jul 05 Javascript
vue实现表格增删改查效果的实例代码
Jul 18 Javascript
原生js jquery ajax请求以及jsonp的调用方法
Aug 04 jQuery
对vue.js中this.$emit的深入理解
Feb 23 Javascript
p5.js码绘“跳动的小正方形”的实现代码
Oct 22 Javascript
原生js实现ajax请求和JSONP跨域请求操作示例
Mar 14 Javascript
多页vue应用的单页面打包方法(内含打包模式的应用)
Jun 11 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面向对象精要总结
2014/11/07 PHP
PHP如何实现跨域
2016/05/30 PHP
JQuery,Extjs,YUI,Prototype,Dojo 等JS框架的区别和应用场景简述
2010/04/15 Javascript
JavaScript实现多维数组的方法
2013/11/20 Javascript
javasript实现密码的隐藏与显示
2015/05/08 Javascript
JS实现从网页顶部掉下弹出层效果的方法
2015/08/06 Javascript
Bootstrap组件学习之导航、标签、面包屑导航(精品)
2016/05/17 Javascript
JS实现HTML表格排序功能
2016/08/05 Javascript
D3.js实现直方图的方法详解
2016/09/25 Javascript
IOS中safari下的select下拉菜单文字过长不换行的解决方法
2016/09/26 Javascript
javascript 判断一个对象为数组的方法
2017/05/03 Javascript
JavaScript实现设置默认日期范围为最近40天的方法分析
2017/07/12 Javascript
JS实现点击发送验证码 xx秒后重新发送功能
2019/07/30 Javascript
微信小程序学习总结(二)样式、属性、模板操作分析
2020/06/04 Javascript
vue treeselect获取当前选中项的label实例
2020/08/31 Javascript
[45:32]Liquid vs LGD 2018国际邀请赛淘汰赛BO3 第二场 8.23
2018/08/24 DOTA
python清除字符串里非字母字符的方法
2015/07/02 Python
python 捕获 shell/bash 脚本的输出结果实例
2017/01/04 Python
利用python模拟sql语句对员工表格进行增删改查
2017/07/05 Python
Windows下anaconda安装第三方包的方法小结(tensorflow、gensim为例)
2018/04/05 Python
解决pycharm回车之后不能换行或不能缩进的问题
2019/01/16 Python
Python supervisor强大的进程管理工具的使用
2019/04/24 Python
pyqt5 使用label控件实时显示时间的实例
2019/06/14 Python
python实现控制COM口的示例
2019/07/03 Python
python爬虫 2019中国好声音评论爬取过程解析
2019/08/26 Python
详解Html5微信支付爬坑之路
2018/07/24 HTML / CSS
香港钟表珠宝首饰商城:OneMallTime网摩间
2016/10/14 全球购物
泰国王权免税店官方网站:KingPower
2019/03/11 全球购物
日本最大的购物网站乐天市场国际版:Rakuten Global Market(支持中文)
2020/02/03 全球购物
设备动力科岗位职责范本
2014/02/23 职场文书
制药工程专业职业生涯规划范文
2014/03/10 职场文书
《大江保卫战》教学反思
2014/04/11 职场文书
写给父母的感谢信
2015/01/22 职场文书
主题班会开场白
2015/06/01 职场文书
励志正能量20句:送给所有为梦想拼搏的人
2019/11/11 职场文书
实例讲解Python中sys.argv[]的用法
2021/06/03 Python