Commit 32c49f58 authored by yanzg's avatar yanzg

修改公式和计算帮助类

parent a5e164b4
package com.yanzuoguang.util.helper; package com.yanzuoguang.util.helper;
import java.util.ArrayList; import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** /**
* 公式计算 * 浮点数计算
* *
* @author 颜佐光 * @author 颜佐光
*/ */
public class CalcHelper { public class CalcHelper {
private static final String REGEX_DOUBLE = "^[-+]?[0-9]*\\.?[0-9]+$"; private static final int DEF_DIV_SCALE = 10;
private static final String REGEX_QUOT = "(^.*?)\\((.+?)\\)(.*?$)";
private static final String REGEX_CALC_ADD_PLUS = "(^.*?)([+\\-])(.*?$)";
private static final String REGEX_CALC_MULTIPLY_MOD = "(^.*?)([*/])(.*?$)";
private static final String REGEX_CALC_TAG = "[+\\-*/()]+";
private static final String EMPTY_CHAR = " ";
public static String TEMP_VAR_NAME = "@temp";
private static CalcHelper calcInstance = new CalcHelper();
/**
* 公式参数获取
*/
public interface CalcParameter {
/** /**
* 获取参数值 * 相加
* *
* @param parameterName 获取参数值的名称 * @param d1
* @param d2
* @return * @return
*/ */
double getValue(String parameterName); public static double add(double d1, double d2) {
BigDecimal b1 = new BigDecimal(Double.toString(d1));
BigDecimal b2 = new BigDecimal(Double.toString(d2));
return b1.add(b2).doubleValue();
} }
/** /**
* 获取excel列序号 * 相减
* *
* @param columnName * @param d1
* @param d2
* @return * @return
*/ */
public static final int getExcelIndex(String columnName) { public static double sub(double d1, double d2) {
columnName = columnName.toLowerCase(); BigDecimal b1 = new BigDecimal(Double.toString(d1));
if (!columnName.matches("^[a-z]+$")) { BigDecimal b2 = new BigDecimal(Double.toString(d2));
throw new RuntimeException("变量名" + columnName + "不支持"); return b1.subtract(b2).doubleValue();
}
// 从名称转换列序号
int formulaColumnIndex = 0;
char[] chs = new char[columnName.length()];
columnName.getChars(0, columnName.length() , chs, 0);
for (int i = 0; i < chs.length; i++) {
formulaColumnIndex = formulaColumnIndex * 26 + (chs[i] - 'a' + 1);
}
formulaColumnIndex--;
return formulaColumnIndex;
}
/**
* 计算公式
*
* @param formula 公式内容,支持括号、空格、数字、+、-、*、/、变量名,如: A * ( B + C )
* @return 运算后的结果
*/
public static double calc(String formula) {
return calcInstance.calRun(formula, StringHelper.EMPTY, null);
} }
/** /**
* 计算公式 * 相乘
* *
* @param formula 公式内容,支持括号、空格、数字、+、-、*、/、变量名,如: A * ( B + C ) * @param d1
* @param calcParameter 获取变量值 * @param d2
* @return 运算后的结果 * @return
*/
public static double calc(String formula, CalcParameter calcParameter) {
return calcInstance.calRun(formula, StringHelper.EMPTY, calcParameter);
}
/**
* 计算公式
*
* @param formula 公式内容,支持括号、空格、数字、+、-、*、/、变量名,如: A * ( B + C )
* @param tempName 临时变量名称
* @param calcParameter 获取变量值
* @return 运算后的结果
*/
public static double calc(String formula, String tempName, CalcParameter calcParameter) {
return calcInstance.calRun(formula, tempName, calcParameter);
}
/**
* 计算公式
*
* @param formula 公式内容,支持括号、空格、数字、+、-、*、/、变量名,如: A * ( B + C )
* @param tempName 临时变量名称
* @param calcParameter 获取变量值
* @return 运算后的结果
*/ */
private double calRun(String formula, String tempName, CalcParameter calcParameter) { public static double mul(double d1, double d2) {
if (StringHelper.isEmpty(formula)) { BigDecimal b1 = new BigDecimal(Double.toString(d1));
return 0; BigDecimal b2 = new BigDecimal(Double.toString(d2));
} return b1.multiply(b2).doubleValue();
tempName = StringHelper.getFirst(tempName, TEMP_VAR_NAME);
// 去掉公式空格
formula = formula.replaceAll(EMPTY_CHAR, "");
// 获取所有的变量名称
List<String> varNames = getVarNames(formula);
// 获取所有变量值
Map<String, Double> varValues = getVarValues(varNames, calcParameter);
// 返回计算结果
return calcProc(formula, tempName, varValues);
}
/**
* 获取变量表
*
* @param formula 输入等式的右边
**/
private List<String> getVarNames(String formula) {
List<String> list = new ArrayList<>();
//清理所有运算符,并且包含多个运算符号时,将多个运算符号当成一个运算符号处理
String formulaTo = formula.replaceAll(REGEX_CALC_TAG, EMPTY_CHAR);
String[] items = formulaTo.split(EMPTY_CHAR);
for (String item : items) {
// 判断是否是空字符串、纯数字,是则不属于变量
if (StringHelper.isEmpty(item) || item.matches(REGEX_DOUBLE)) {
continue;
}
list.add(item);
}
return list;
}
/**
* 获取所有变量值
*
* @param varNames 变量名称列表
* @param calcParameter 获取变量值
* @return 变量值
*/
private Map<String, Double> getVarValues(List<String> varNames, CalcParameter calcParameter) {
// 获取所有的变量值
Map<String, Double> varValues = new HashMap<>(varNames.size());
for (String name : varNames) {
if (varValues.containsKey(name) || calcParameter == null) {
continue;
}
double value = calcParameter.getValue(name);
varValues.put(name, value);
}
return varValues;
} }
/** /**
* 最终计算结果 * 相除
* *
* @param formula 公式 * @param d1
* @param tempName 临时变量名称 * @param d2
* @param varValues 变量值
* @return * @return
*/ */
private double calcProc(String formula, String tempName, Map<String, Double> varValues) { public static double div(double d1, double d2) {
double ret = 0; return div(d1, d2, DEF_DIV_SCALE);
if (formula.matches(REGEX_QUOT)) {
// 获取第一个括号和最后一个括号
Matcher matcher = getMatcher(REGEX_QUOT, formula);
double quotResult = calcProc(matcher.group(2), tempName, varValues);
String mutualKey = TEMP_VAR_NAME + varValues.size();
varValues.put(mutualKey, quotResult);
String formulaTo = matcher.group(1) + mutualKey + matcher.group(3);
ret = calcProc(formulaTo, tempName, varValues);
} else if (formula.matches(REGEX_CALC_ADD_PLUS)) {
// 判断是否包含+-运算符号
Matcher matcher = getMatcher(REGEX_CALC_ADD_PLUS, formula);
double leftResult = calcProc(matcher.group(1), tempName, varValues);
double rightResult = calcProc(matcher.group(3), tempName, varValues);
ret = calcItem(matcher.group(2), leftResult, rightResult);
} else if (formula.matches(REGEX_CALC_MULTIPLY_MOD)) {
// 判断是否包含*/运算符号
Matcher matcher = getMatcher(REGEX_CALC_MULTIPLY_MOD, formula);
double leftResult = calcProc(matcher.group(1), tempName, varValues);
double rightResult = calcProc(matcher.group(3), tempName, varValues);
ret = calcItem(matcher.group(2), leftResult, rightResult);
} else if (formula.matches(REGEX_DOUBLE)) {
ret = StringHelper.toDouble(formula);
} else {
ret = StringHelper.toDouble(varValues.get(formula));
}
System.out.println("公式: " + formula + " 值" + ret);
return ret;
} }
/** /**
* 匹配正则表达式和公式 * 相除
* *
* @param regex 正则表达式 * @param d1
* @param formula 公式 * @param d2
* @return 匹配后的结果 * @param scale
* @return
*/ */
private Matcher getMatcher(String regex, String formula) { public static double div(double d1, double d2, int scale) {
Pattern p = Pattern.compile(regex); if (scale < 0) {
Matcher matcher = p.matcher(formula); throw new IllegalArgumentException("The scale must be a positive integer or zero");
if (!matcher.find()) {
throw new RuntimeException("正则表达式错误");
}
return matcher;
} }
BigDecimal b1 = new BigDecimal(Double.toString(d1));
BigDecimal b2 = new BigDecimal(Double.toString(d2));
return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
private double calcItem(String flag, double a, double b) {
switch (flag) {
case "+":
return a + b;
case "-":
return a - b;
case "*":
return a * b;
case "/":
return a / b;
default:
return 0;
} }
}
} }
package com.yanzuoguang.util.helper;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 公式计算
*
* @author 颜佐光
*/
public class FormulaHelper {
private static final String REGEX_DOUBLE = "^[-+]?[0-9]*\\.?[0-9]+$";
private static final String REGEX_QUOT = "(^.*?)\\((.+?)\\)(.*?$)";
private static final String REGEX_CALC_ADD_PLUS = "(^.*?)([+\\-])(.*?$)";
private static final String REGEX_CALC_MULTIPLY_MOD = "(^.*?)([*/])(.*?$)";
private static final String REGEX_CALC_TAG = "[+\\-*/()]+";
private static final String EMPTY_CHAR = " ";
public static String TEMP_VAR_NAME = "@temp";
private static FormulaHelper calcInstance = new FormulaHelper();
/**
* 公式参数获取
*/
public interface CalcParameter {
/**
* 获取参数值
*
* @param parameterName 获取参数值的名称
* @return
*/
double getValue(String parameterName);
}
/**
* 获取excel列序号
*
* @param columnName
* @return
*/
public static final int getExcelIndex(String columnName) {
columnName = columnName.toLowerCase();
if (!columnName.matches("^[a-z]+$")) {
throw new RuntimeException("变量名" + columnName + "不支持");
}
// 从名称转换列序号
int formulaColumnIndex = 0;
char[] chs = new char[columnName.length()];
columnName.getChars(0, columnName.length() , chs, 0);
for (int i = 0; i < chs.length; i++) {
formulaColumnIndex = formulaColumnIndex * 26 + (chs[i] - 'a' + 1);
}
formulaColumnIndex--;
return formulaColumnIndex;
}
/**
* 计算公式
*
* @param formula 公式内容,支持括号、空格、数字、+、-、*、/、变量名,如: A * ( B + C )
* @return 运算后的结果
*/
public static double calc(String formula) {
return calcInstance.calRun(formula, StringHelper.EMPTY, null);
}
/**
* 计算公式
*
* @param formula 公式内容,支持括号、空格、数字、+、-、*、/、变量名,如: A * ( B + C )
* @param calcParameter 获取变量值
* @return 运算后的结果
*/
public static double calc(String formula, CalcParameter calcParameter) {
return calcInstance.calRun(formula, StringHelper.EMPTY, calcParameter);
}
/**
* 计算公式
*
* @param formula 公式内容,支持括号、空格、数字、+、-、*、/、变量名,如: A * ( B + C )
* @param tempName 临时变量名称
* @param calcParameter 获取变量值
* @return 运算后的结果
*/
public static double calc(String formula, String tempName, CalcParameter calcParameter) {
return calcInstance.calRun(formula, tempName, calcParameter);
}
/**
* 计算公式
*
* @param formula 公式内容,支持括号、空格、数字、+、-、*、/、变量名,如: A * ( B + C )
* @param tempName 临时变量名称
* @param calcParameter 获取变量值
* @return 运算后的结果
*/
private double calRun(String formula, String tempName, CalcParameter calcParameter) {
if (StringHelper.isEmpty(formula)) {
return 0;
}
tempName = StringHelper.getFirst(tempName, TEMP_VAR_NAME);
// 去掉公式空格
formula = formula.replaceAll(EMPTY_CHAR, "");
// 获取所有的变量名称
List<String> varNames = getVarNames(formula);
// 获取所有变量值
Map<String, Double> varValues = getVarValues(varNames, calcParameter);
// 返回计算结果
return calcProc(formula, tempName, varValues);
}
/**
* 获取变量表
*
* @param formula 输入等式的右边
**/
private List<String> getVarNames(String formula) {
List<String> list = new ArrayList<>();
//清理所有运算符,并且包含多个运算符号时,将多个运算符号当成一个运算符号处理
String formulaTo = formula.replaceAll(REGEX_CALC_TAG, EMPTY_CHAR);
String[] items = formulaTo.split(EMPTY_CHAR);
for (String item : items) {
// 判断是否是空字符串、纯数字,是则不属于变量
if (StringHelper.isEmpty(item) || item.matches(REGEX_DOUBLE)) {
continue;
}
list.add(item);
}
return list;
}
/**
* 获取所有变量值
*
* @param varNames 变量名称列表
* @param calcParameter 获取变量值
* @return 变量值
*/
private Map<String, Double> getVarValues(List<String> varNames, CalcParameter calcParameter) {
// 获取所有的变量值
Map<String, Double> varValues = new HashMap<>(varNames.size());
for (String name : varNames) {
if (varValues.containsKey(name) || calcParameter == null) {
continue;
}
double value = calcParameter.getValue(name);
varValues.put(name, value);
}
return varValues;
}
/**
* 最终计算结果
*
* @param formula 公式
* @param tempName 临时变量名称
* @param varValues 变量值
* @return
*/
private double calcProc(String formula, String tempName, Map<String, Double> varValues) {
double ret = 0;
if (formula.matches(REGEX_QUOT)) {
// 获取第一个括号和最后一个括号
Matcher matcher = getMatcher(REGEX_QUOT, formula);
double quotResult = calcProc(matcher.group(2), tempName, varValues);
String mutualKey = TEMP_VAR_NAME + varValues.size();
varValues.put(mutualKey, quotResult);
String formulaTo = matcher.group(1) + mutualKey + matcher.group(3);
ret = calcProc(formulaTo, tempName, varValues);
} else if (formula.matches(REGEX_CALC_ADD_PLUS)) {
// 判断是否包含+-运算符号
Matcher matcher = getMatcher(REGEX_CALC_ADD_PLUS, formula);
double leftResult = calcProc(matcher.group(1), tempName, varValues);
double rightResult = calcProc(matcher.group(3), tempName, varValues);
ret = calcItem(matcher.group(2), leftResult, rightResult);
} else if (formula.matches(REGEX_CALC_MULTIPLY_MOD)) {
// 判断是否包含*/运算符号
Matcher matcher = getMatcher(REGEX_CALC_MULTIPLY_MOD, formula);
double leftResult = calcProc(matcher.group(1), tempName, varValues);
double rightResult = calcProc(matcher.group(3), tempName, varValues);
ret = calcItem(matcher.group(2), leftResult, rightResult);
} else if (formula.matches(REGEX_DOUBLE)) {
ret = StringHelper.toDouble(formula);
} else {
ret = StringHelper.toDouble(varValues.get(formula));
}
System.out.println("公式: " + formula + " 值" + ret);
return ret;
}
/**
* 匹配正则表达式和公式
*
* @param regex 正则表达式
* @param formula 公式
* @return 匹配后的结果
*/
private Matcher getMatcher(String regex, String formula) {
Pattern p = Pattern.compile(regex);
Matcher matcher = p.matcher(formula);
if (!matcher.find()) {
throw new RuntimeException("正则表达式错误");
}
return matcher;
}
private double calcItem(String flag, double a, double b) {
switch (flag) {
case "+":
return a + b;
case "-":
return a - b;
case "*":
return a * b;
case "/":
return a / b;
default:
return 0;
}
}
}
package helper; package helper;
import com.yanzuoguang.util.helper.CalcHelper; import com.yanzuoguang.util.helper.FormulaHelper;
import org.junit.Test; import org.junit.Test;
public class TestCalcHelper { public class TestFormulaHelper {
@Test @Test
public void test() { public void test() {
System.out.println(CalcHelper.calc("120 + 2 * ( a + b * d )", new CalcHelper.CalcParameter() { System.out.println(FormulaHelper.calc("120 + 2 * ( a + b * d )", new FormulaHelper.CalcParameter() {
@Override @Override
public double getValue(String parameterName) { public double getValue(String parameterName) {
switch (parameterName){ switch (parameterName){
...@@ -27,7 +27,7 @@ public class TestCalcHelper { ...@@ -27,7 +27,7 @@ public class TestCalcHelper {
@Test @Test
public void test1() { public void test1() {
System.out.println(CalcHelper.calc("= a * 120 + 2 * ( a + b * d )", new CalcHelper.CalcParameter() { System.out.println(FormulaHelper.calc("= a * 120 + 2 * ( a + b * d )", new FormulaHelper.CalcParameter() {
@Override @Override
public double getValue(String parameterName) { public double getValue(String parameterName) {
switch (parameterName){ switch (parameterName){
...@@ -46,7 +46,7 @@ public class TestCalcHelper { ...@@ -46,7 +46,7 @@ public class TestCalcHelper {
@Test @Test
public void test3() { public void test3() {
System.out.println(CalcHelper.calc("a * 0.006", new CalcHelper.CalcParameter() { System.out.println(FormulaHelper.calc("a * 0.006", new FormulaHelper.CalcParameter() {
@Override @Override
public double getValue(String parameterName) { public double getValue(String parameterName) {
switch (parameterName){ switch (parameterName){
...@@ -61,9 +61,9 @@ public class TestCalcHelper { ...@@ -61,9 +61,9 @@ public class TestCalcHelper {
@Test @Test
public void test2() { public void test2() {
System.out.println(CalcHelper.getExcelIndex("aa")); System.out.println(FormulaHelper.getExcelIndex("aa"));
System.out.println(CalcHelper.getExcelIndex("ba")); System.out.println(FormulaHelper.getExcelIndex("ba"));
System.out.println(CalcHelper.getExcelIndex("ab")); System.out.println(FormulaHelper.getExcelIndex("ab"));
System.out.println(CalcHelper.getExcelIndex("a")); System.out.println(FormulaHelper.getExcelIndex("a"));
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment