首页 > 其他分享 >算数表达式求值 算数表达式字符串求值

算数表达式求值 算数表达式字符串求值

时间:2022-09-28 19:25:53浏览次数:51  
标签:arr return String 运算符 result 算数 求值 expression 表达式

package com.bison.tracecode.utils;

import cn.hutool.core.util.NumberUtil;

import java.math.RoundingMode;
import java.util.Collections;
import java.util.Stack;

/**
 * @author XXX
 * @date 2022/7/4
 **/

/**
 * 算数表达式求值
 * 直接调用Calculator的类方法conversion()
 * 传入算数表达式,将返回一个浮点值结果
 * 如果计算过程错误,将返回一个NaN
 */
public class CalculatorUtils {
	private Stack<String> postfixStack = new Stack<String>();// 后缀式栈
	private Stack<Character> opStack = new Stack<Character>();// 运算符栈
	private int[] operatPriority = new int[]{0, 3, 2, 1, -1, 1, 0, 2};// 运用运算符ASCII码-40做索引的运算符优先级

	public static String conversion(String expression) {
		String result = "0";
		CalculatorUtils cal = new CalculatorUtils();
		try {
			expression = transform(expression);
			result = cal.calculate(expression);
		} catch (Exception e) {
			// e.printStackTrace();
			// 运算错误返回NaN
			return "";
		}
		// return new String().valueOf(result);
		return result;
	}

	/**
	 * 将表达式中负数的符号更改
	 *
	 * @param expression 例如-2+-1*(-3E-2)-(-1) 被转为 ~2+~1*(~3E~2)-(~1)
	 * @return
	 */
	private static String transform(String expression) {
		char[] arr = expression.toCharArray();
		for (int i = 0; i < arr.length; i++) {
			if (arr[i] == '-') {
				if (i == 0) {
					arr[i] = '~';
				} else {
					char c = arr[i - 1];
					if (c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == 'E' || c == 'e') {
						arr[i] = '~';
					}
				}
			}
		}
		if (arr[0] == '~' || arr[1] == '(') {
			arr[0] = '-';
			return "0" + new String(arr);
		} else {
			return new String(arr);
		}
	}

	/**
	 * 按照给定的表达式计算
	 *
	 * @param expression 要计算的表达式例如:5+12*(3+5)/7
	 * @return
	 */
	public String calculate(String expression) {
		Stack<String> resultStack = new Stack<String>();
		prepare(expression);
		Collections.reverse(postfixStack);// 将后缀式栈反转
		String firstValue, secondValue, currentValue;// 参与计算的第一个值,第二个值和算术运算符
		while (!postfixStack.isEmpty()) {
			currentValue = postfixStack.pop();
			if (!isOperator(currentValue.charAt(0))) {// 如果不是运算符则存入操作数栈中
				currentValue = currentValue.replace("~", "-");
				resultStack.push(currentValue);
			} else {// 如果是运算符则从操作数栈中取两个值和该数值一起参与运算
				secondValue = resultStack.pop();
				firstValue = resultStack.pop();

				// 将负数标记符改为负号
				firstValue = firstValue.replace("~", "-");
				secondValue = secondValue.replace("~", "-");

				String tempResult = calculate(firstValue, secondValue, currentValue.charAt(0));
				resultStack.push(tempResult);
			}
		}
		return resultStack.pop();
	}

	/**
	 * 数据准备阶段将表达式转换成为后缀式栈
	 *
	 * @param expression
	 */
	private void prepare(String expression) {
		opStack.push(',');// 运算符放入栈底元素逗号,此符号优先级最低
		char[] arr = expression.toCharArray();
		int currentIndex = 0;// 当前字符的位置
		int count = 0;// 上次算术运算符到本次算术运算符的字符的长度便于或者之间的数值
		char currentOp, peekOp;// 当前操作符和栈顶操作符
		for (int i = 0; i < arr.length; i++) {
			currentOp = arr[i];
			if (isOperator(currentOp)) {// 如果当前字符是运算符
				if (count > 0) {
					postfixStack.push(new String(arr, currentIndex, count));// 取两个运算符之间的数字
				}
				peekOp = opStack.peek();
				if (currentOp == ')') {// 遇到反括号则将运算符栈中的元素移除到后缀式栈中直到遇到左括号
					while (opStack.peek() != '(') {
						postfixStack.push(String.valueOf(opStack.pop()));
					}
					opStack.pop();
				} else {
					while (currentOp != '(' && peekOp != ',' && compare(currentOp, peekOp)) {
						postfixStack.push(String.valueOf(opStack.pop()));
						peekOp = opStack.peek();
					}
					opStack.push(currentOp);
				}
				count = 0;
				currentIndex = i + 1;
			} else {
				count++;
			}
		}
		if (count > 1 || (count == 1 && !isOperator(arr[currentIndex]))) {// 最后一个字符不是括号或者其他运算符的则加入后缀式栈中
			postfixStack.push(new String(arr, currentIndex, count));
		}

		while (opStack.peek() != ',') {
			postfixStack.push(String.valueOf(opStack.pop()));// 将操作符栈中的剩余的元素添加到后缀式栈中
		}
	}

	/**
	 * 判断是否为算术符号
	 *
	 * @param c
	 * @return
	 */
	private boolean isOperator(char c) {
		return c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')';
	}

	/**
	 * 利用ASCII码-40做下标去算术符号优先级
	 *
	 * @param cur
	 * @param peek
	 * @return
	 */
	public boolean compare(char cur, char peek) {// 如果是peek优先级高于cur,返回true,默认都是peek优先级要低
		boolean result = false;
		if (operatPriority[(peek) - 40] >= operatPriority[(cur) - 40]) {
			result = true;
		}
		return result;
	}

	/**
	 * 按照给定的算术运算符做计算
	 *
	 * @param firstValue
	 * @param secondValue
	 * @param currentOp
	 * @return
	 */
	private String calculate(String firstValue, String secondValue, char currentOp) {
		String result = "";
		switch (currentOp) {
			case '+':
				result = String.valueOf(NumberUtil.add(firstValue, secondValue));
				break;
			case '-':
				result = String.valueOf(NumberUtil.sub(firstValue, secondValue));
				break;
			case '*':
				result = String.valueOf(NumberUtil.mul(firstValue, secondValue));
				break;
			case '/':
				result = String.valueOf(NumberUtil.div(firstValue, secondValue, 0, RoundingMode.UP));
				break;
		}
		return result;
	}
}


标签:arr,return,String,运算符,result,算数,求值,expression,表达式
From: https://www.cnblogs.com/fuqian/p/16739274.html

相关文章

  • python-正则表达式re模块
    07、正则表达式学习正则表达式操作字符串re模块是用C语言写的没匹配速度非常快其中compile函数根据一个模式字符串和可选的标志参数生成一个正则表达式对象,该对象拥有......
  • 实验1 C语言开发环境使用和数据类型、运算符、表达式
    #include<iostream>#include<string>#include<vector>intmain(){usingnamespacestd;strings1;//创建一个string对象strings2{"cplusplus"};//......
  • java8实战二:Lambda 表达式
    Lambda表达式前片文章讲到,使用匿名类来表示不同的行为并不令人满意:代码十分啰嗦,这会影响程序员在实践中使用行为参数化的积极性。在本章中,我们会教给你Java8中解决这个......
  • .NET教程 - 字符串 & 编码 & 正则表达式(String & Encoding & Regular Express)
    更新记录转载请注明出处:2022年9月28日发布。2022年9月28日从笔记迁移到博客。System.char说明singleUnicodecharacteraliasestheSystem.Charstructcharc......
  • Swift 范围表达式
    Swift范围表达式不同类型的范围运算符一个**范围**是两个数值区间之间的一系列值。Range实例可以使用**范围运算符**.Swift包含几个范围运算符,它们是表示值......
  • spel 表达式语言 注入
    /**作者:呆萌老师*☑csdn认证讲师*☑51cto高级讲师*☑腾讯课堂认证讲师*☑网易云课堂认证讲师*☑华为开发者学堂认证讲师*☑爱奇艺千人名师计划成员*在这里给大家......
  • 函数声明和函数表达式声明的区别
    函数声明:sum();//10functionsum(){console.log(10)}表达式声明   s();//报错sisnotafunction   vars=function(){console.log(20)}在预解析的过......
  • 身份证号、手机号、邮箱正则表达式
    邮箱验证:varregEmail=/^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/;手机号验证:varregMobile=/^(0|86|17951)?(13[0-9]|15[012356789]|17[678]|18......
  • LeetCode[150] 逆波兰表达式求值
    1逆波兰表达式求值1.1题目描述        根据逆波兰表示法,求表达式的值。有效的算符包括+、-、*、/。每个运算对象可以是整数,也可以是另一个逆波兰表达式。 ......
  • 正则表达式语法
    正则表达式语法元字符-转义符\需要用到转义符号的字符有一下:.*+()/?[]^{}元字符-字符匹配符符号符号示例解释[]可接收的字符列表[efgh]e、f、g、h......