我的一位好友需要软件里面内置一个小插件,可以根据用户输入的简单公式引导用户进行输入和计算,所以简单地写了一个原理实现。主要用到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