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 页面自动加载函数(兼容多浏览器)
May 18 Javascript
parseInt parseFloat js字符串转换数字
Aug 01 Javascript
js点击事件链接的问题解决
Apr 25 Javascript
JavaScript中字符串拼接的基本方法
Jul 07 Javascript
Javascript类型系统之undefined和null浅析
Jul 13 Javascript
JS仿hao123导航页面图片轮播效果
Sep 01 Javascript
原生js实现addclass,removeclass,toggleclasss实例
Nov 24 Javascript
Bootstrap源码学习笔记之bootstrap进度条
Dec 24 Javascript
Angular指令封装jQuery日期时间插件datetimepicker实现双向绑定示例
Jan 22 Javascript
Vue2.0使用过程常见的一些问题总结学习
Apr 10 Javascript
webpack是如何实现模块化加载的方法
Nov 06 Javascript
Vue环境搭建+VSCode+Win10的详细教程
Aug 19 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的FTP学习(一)[转自奥索]
2006/10/09 PHP
php下使用SMTP发邮件的代码
2008/01/10 PHP
让PHP支持断点续传的源码
2010/05/16 PHP
PHP实现深度优先搜索算法(DFS,Depth First Search)详解
2017/09/16 PHP
php实现的生成迷宫与迷宫寻址算法完整实例
2017/11/06 PHP
PHP使用星号替代用户名手机和邮箱的实现代码
2018/02/07 PHP
PHP生成二维码与识别二维码的方法详解【附源码下载】
2019/03/07 PHP
用js遍历 table的脚本
2008/07/23 Javascript
基于jquery实现全屏滚动效果
2015/11/26 Javascript
Bootstrap框架结合jQuery仿百度换肤功能实例解析
2016/09/17 Javascript
angular ng-repeat数组中的数组实例
2017/02/18 Javascript
jQuery中animate()的使用方法及解决$(”body“).animate({“scrollTop”:top})不被Firefox支持的问题
2017/04/04 jQuery
AngularJS实现根据不同条件显示不同控件
2017/04/20 Javascript
详解Angular 4.x Injector
2017/05/04 Javascript
微信小程序 自定义Toast实例代码
2017/06/12 Javascript
Angular 表单控件示例代码
2017/06/26 Javascript
JavaScript 有用的代码片段和 trick
2018/02/22 Javascript
vue富文本框(插入文本、图片、视频)的使用及问题小结
2018/08/17 Javascript
bootstrap table表格插件之服务器端分页实例代码
2018/09/12 Javascript
Vue全局loading及错误提示的思路与实现
2019/08/09 Javascript
layui--select使用以及下拉框实现键盘选择的例子
2019/09/24 Javascript
vue 解决data中定义图片相对路径页面不显示的问题
2020/08/13 Javascript
Python线程详解
2015/06/24 Python
详细介绍Python的鸭子类型
2016/09/12 Python
解决python3中cv2读取中文路径的问题
2018/12/05 Python
TensorFlow自定义损失函数来预测商品销售量
2020/02/05 Python
Python利用FFT进行简单滤波的实现
2020/02/26 Python
Python退出时强制运行一段代码的实现方法
2020/04/29 Python
使用CSS3实现SVG路径描边动画效果入门教程
2019/10/21 HTML / CSS
美国最大的珠宝商之一:Littman Jewelers
2016/11/13 全球购物
Footshop罗马尼亚:最好的运动鞋选择
2019/09/10 全球购物
毕业班联欢会主持词
2014/03/27 职场文书
车间主任岗位职责
2015/02/03 职场文书
个人工作保证书
2015/02/28 职场文书
人民币使用说明书
2019/04/17 职场文书
ajax请求前端跨域问题原因及解决方案
2021/10/16 Javascript