1. 程式人生 > >使用Java寫公式計算器

使用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