使用Java写公式计算器

我的一位好友需要软件里面内置一个小插件,可以根据用户输入的简单公式引导用户进行输入和计算,所以简单地写了一个原理实现。主要用到Java字符串处理和数据结构的栈思想,难度不大但要非常细心。

原理如下:

1、对公式以等号为分隔符进行左右分割,然后取得公式右边字符串

2、对公式右边字符串进行运算符(+、-、*、/、(、))和常数的去除,然后分割出变量名

3、请求用户输入各变量的值,用用户输入值取代字符串的对应变量,使得公式变成纯数字和纯运算符构成的字符串。

4、最复杂的一环:寻找第一个右括号(想到于找到栈顶),然后倒过来找左括号(如公式格式正确则必然同时是最后一个左括号),左括号和右括号作为一个整体提取作为子字符串。子字符串里面先找乘法和除法的子子字符串进行计算,再找加法和除法的子子字符串进行计算(按运算符查找,并找到符号两边的数值),然后运算完之后替换回去作为新的子字符串,直到子字符串没有运算符则结束。

5、子字符串为括号内部运算的最终结果,用该结果替换整个子字符串,调到第1步开始重复。直到公式没有一个运算符停止

实现代码:

package com.test.calc;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.Stack;
import java.util.function.Consumer;

/**公式计算器**/
public class EquationCalculator {

	/** 变量集合 **/
	private static List<String> varList = new LinkedList<>();
	/** 变量和值的key-value **/
	private static Map<String, Float> varListWithValue = new HashMap<>();

	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		System.out.println("请输入你需要计算的公式:");
		String formula = scanner.nextLine().replaceAll(" ", "");
		//String formula = "f=k * (((m1 + m2) * (40 * x + 60 * y)) + 100) * m2 / (G1 + G2)".replaceAll(" ", ""); fortest
		String equalationLeft = formula.split("=")[0];
		String equalationRight = formula.split("=")[1];
		/** 获取变量表: **/
		getVarList(equalationRight);
		/** 给变量赋值 **/
		assignmentVarList(varList);
		/** 代回公式进行替换 **/
		String newFormula = replaceEquation(formula);
		/** 进行计算 **/
		System.out.println();
		float result = calc(newFormula);
		System.out.println("最终结果:" + equalationLeft + "=" + result);
	}

	/** 进行计算 **/
	private static float calc(String newFormula) {
		boolean stillHaveCalcSymbol = false;
		do{
			//System.out.println("before:" + newFormula);
			/** 寻找最后一个左括号里面到第一个右括号里面1的内容 **/
			char formulaArray[] = newFormula.toCharArray();
			for (int i = 0; i < formulaArray.length; i++) {
				if (formulaArray[i] == '+' || formulaArray[i] == '-'
						|| formulaArray[i] == '*' || formulaArray[i] == '/'
						|| formulaArray[i] == '(' || formulaArray[i] == ')') {
					stillHaveCalcSymbol = true;
				} else {
					stillHaveCalcSymbol = false;
				}
			}
			if (stillHaveCalcSymbol) {
				String resultFormula = "";
				//找最内层的括号里面的内容出来(含括号)
				for (int i = 0; i < formulaArray.length; i++) {
					if (formulaArray[i] == ')') {
						int begin = 0;
						for (int j = i; j >= 0; j--) {
							if (formulaArray[j] == '(') {
								begin = j;
								break;
							}
						}
						String calcString = newFormula.substring(begin, i + 1);
						resultFormula = newFormula.replace(calcString, calcProc(calcString) + "");
						//System.out.println(calcString);
						break;
					}
				}
				newFormula = resultFormula;
			}
		} while(stillHaveCalcSymbol);
		//最后得到普通的顺序无括号公式:
		System.out.println(newFormula);
		//最后一次计算:
		float result = calcProc("(" + newFormula.split("=")[1] + ")"); 
		return result;
	}

	/**详细计算过程**/
	private static float calcProc(String calcString) {
//		if(calcString.contains("=")){
//			calcString = calcString.split("=")[1];
//		}
		//calcString = calcString.replace("(", "");
		//calcString = calcString.replace(")", "");
	
		String calcSymbol[] = {"\\*", "\\/", "\\+", "\\-"};
		char calcSymbolChar[] = {'*', '/', '+', '-'};
		boolean haveSymbol = true;
		float result = 0f;
		while(haveSymbol){
			System.out.println("calcStr:" + calcString);
			char calcCharArr[] = calcString.toCharArray();
			result = 0f;
			for (int i = 0; i < calcSymbol.length; i++) {
				boolean alreadyFind = false;
				for(int j = 0; j < calcCharArr.length; j++){
					if(calcCharArr[j] == calcSymbolChar[i]){
						//System.out.println("找到了" + calcSymbolChar[i]);
						//以符号为中心,以左右两边的其他符号为边界找到两边的数
						float num1 = 0f;
						float num2 = 0f;
						int bottom = 0;
						for(int k = j - 1; k >= 0 && (calcCharArr[k] >= '0' && calcCharArr[k] <= '9' || calcCharArr[k] == '.') ; k--){
							//System.out.println(calcCharArr[k] + "");
							bottom = k;
						}
						//System.out.println("[j, bottom]:" + String.format("[%d, %d]", j, bottom));
						num1 = Float.valueOf(calcString.substring(bottom, j));
						System.out.println("num1:" + num1);
						int top = 0;
						for(int k = j + 1; k < calcString.length() && (calcCharArr[k] >= '0' && calcCharArr[k] <= '9' || calcCharArr[k] == '.'); k++){
							top = k;
						}
						num2 = Float.valueOf(calcString.substring(j + 1, top + 1));
						System.out.println("num2:" + num2);
						switch(calcSymbolChar[i]){
							case '*':
								result = num1 * num2;
								break;
							case '/':
								result = num1 / num2;
								break;
							case '+':
								result = num1 + num2;
								break;
							case '-':
								result = num1 - num2;
								break;
						}
						//System.out.println("bottom to top:" + calcString.substring(bottom + 1, top + 1)); 
						calcString = calcString.replace(calcString.substring(bottom, top + 1), String.format("%.5f", result));
						//System.out.println("end_calcStr:" + calcString);
						alreadyFind = true;
						break;
					}
				}
				if(alreadyFind) break;
			}
			haveSymbol = false;
			if(calcString.contains("*") || calcString.contains("/") || calcString.contains("+") || calcString.contains("-")){
				haveSymbol = true;
				//System.out.println("找到");
			} else {
				//System.out.println("找不到");
			}
		}
		//System.out.println("result:" + result);
		return result;
	}

	/** 代回公式进行替换 **/
	private static String replaceEquation(String formula) {
		String newFormula = new String(formula);
		for (String key : varList) {
			newFormula = newFormula.replaceAll(key, varListWithValue.get(key)
					+ "");
		}
		System.out.println(newFormula);
		return newFormula;
	}

	/**
	 * 给变量赋值
	 * 
	 * @param varList
	 *            变量列表
	 **/
	private static void assignmentVarList(List<String> varList) {
		System.out.println("请输入各变量的对应值");
		Scanner scanner = new Scanner(System.in);
		for (String key : varList) {
			System.out.print(key + "'s value is:");
			varListWithValue.put(key, scanner.nextFloat());
		}
		/*for (String key : varList) {
			System.out.println("key:" + key + ", value:"
					+ varListWithValue.get(key));
		}*/
	}

	/**
	 * 获取变量表
	 * 
	 * @param equalationRight
	 *            输入等式的右边
	 **/
	private static void getVarList(String equalationRight) {
		System.out.println("等式右边:" + equalationRight);
		char[] formulaCharArr;
		formulaCharArr = equalationRight.toCharArray();
		//清理所有运算符
		for (int i = 0; i < formulaCharArr.length; i++) {
			if (formulaCharArr[i] == '+' || formulaCharArr[i] == '-'
					|| formulaCharArr[i] == '*' || formulaCharArr[i] == '/'
					|| formulaCharArr[i] == '(' || formulaCharArr[i] == ')') {
				formulaCharArr[i] = ' ';
			}
		}
		/*String temp = "";
		for (int i = 0; i < formulaCharArr.length; i++) {
			if (formulaCharArr[i] == ' ') {
				String content = temp.trim();
				if (content.length() > 0) {
					boolean okGo = true;
					if(content.charAt(0) >= '0' && content.charAt(0) <= '9'){
						okGo = false;
					}
					if (okGo) {
						varList.add(content);
					}
				}
				temp = "";
			} else {
				temp += formulaCharArr[i];
			}
		}*/
		String pa[] = new String(formulaCharArr).split(" ");
		for(String temp : pa){
			if(temp != null && temp != "" && !temp.isEmpty()){
				boolean okGo = true;
				if(temp.charAt(0) >= '0' && temp.charAt(0) <= '9'){
					okGo = false;
				}
				if (okGo) {
					varList.add(temp);
				}
			}
		}
		System.out.println("变量列表:");
		for (int h = 0; h < varList.size(); h++) {
			String var = varList.get(h);
			System.out.println(var);
		}
	}

}

测试1:

请输入你需要计算的公式:
j=b*y+a
等式右边:b*y+a
变量列表:
b
y
a
请输入各变量的对应值
b's value is:55
y's value is:66
a's value is:77
j=55.0*66.0+77.0

j=55.0*66.0+77.0
calcStr:(55.0*66.0+77.0)
num1:55.0
num2:66.0
calcStr:(3630.00000+77.0)
num1:3630.0
num2:77.0
最终结果:j=3707.0

测试2:

请输入你需要计算的公式:
f=k * (((m1 + m2) * (40 * x + 60 * y)) + 100) * m2 / (G1 + G2) + (G3 * G4)
等式右边:k*(((m1+m2)*(40*x+60*y))+100)*m2/(G1+G2)+(G3*G4)
变量列表:
k
m1
m2
x
y
m2
G1
G2
G3
G4
请输入各变量的对应值
k's value is:1.1
m1's value is:2.232
m2's value is:3.333
x's value is:4.567
y's value is:31.44
m2's value is:54.22
G1's value is:5454
G2's value is:111
G3's value is:1112
G4's value is:3333
f=1.1*(((2.232+54.22)*(40*4.567+60*31.44))+100)*54.22/(5454.0+111.0)+(1112.0*3333.0)

calcStr:(2.232+54.22)
num1:2.232
num2:54.22
calcStr:(40*4.567+60*31.44)
num1:40.0
num2:4.567
calcStr:(182.67999+60*31.44)
num1:60.0
num2:31.44
calcStr:(182.67999+1886.40002)
num1:182.68
num2:1886.4
calcStr:(56.452*2069.08)
num1:56.452
num2:2069.08
calcStr:(116803.71+100)
num1:116803.71
num2:100.0
calcStr:(5454.0+111.0)
num1:5454.0
num2:111.0
calcStr:(1112.0*3333.0)
num1:1112.0
num2:3333.0
f=1.1*116903.71*54.22/5565.0+3706296.0
calcStr:(1.1*116903.71*54.22/5565.0+3706296.0)
num1:1.1
num2:116903.71
calcStr:(128594.08594*54.22/5565.0+3706296.0)
num1:128594.086
num2:54.22
calcStr:(6972371.50000/5565.0+3706296.0)
num1:6972371.5
num2:5565.0
calcStr:(1252.89697+3706296.0)
num1:1252.897
num2:3706296.0
最终结果:f=3707549.0
 

猜你喜欢

转载自blog.csdn.net/cjzjolly/article/details/85015137