package cn.com.worksoft.util.expression;
import java.util.Arrays;
import cn.com.worksoft.util.log.LogFactory;
import cn.com.worksoft.util.log.Logger;
/**
*
* @author XING
*
* Create time 2004-12-2 16:52:48
*
* 本類的運算邏輯是 分為以下幾個步驟:
* 1、格式化所輸入的算式(去掉所有空格,+-符號前面如果沒有數字就補0,×/符號前面如果沒有數字就補1,^~符號后面如果沒有數字就補2,其它如果出現前后缺少的情況就報錯)
* 2、獲得的算式串,如A; 3、獲取所有運算符號,尋找第一個需要運算的符號,基本規則是,找到最里層的(),然后在其內部找,^~ > /* > +-
* ,同類型的就從做至右運算; 4、獲取該運算符號的兩端變量,進行運算得出結果,將結果回填回去; 5、取得了新的運算串,存入A;
* 6、重復2直到A中沒有運算符號為止; 7、得到結果。
*
* 更改所生成類型注釋的模板為 窗口 > 首選項 > Java > 代碼生成 > 代碼和注釋
*/
public final class TExpression {
public final static String ADD = "\\\\+";
public final static String DECREASE = "\\\\-";
public final static String[] DefaultVars = new String[]
{
"+",
"-",
"*",
"/",
"^",
"~", };
public final static String DIVIDE = "/";
public final static String FU = "GXFU";
public final static String LBRACKET = "\\\\(";
public final static String MULTIPLY = "\\\\*";
public final static String PERCENT = "%";
public final static String POWER = "\\\\^";
public final static String RBRACKET = "\\\\)";
public final static String SQRT = "~";
private final static Logger gLogger = LogFactory.defaultFacotry()
.createNewLogger();
/**
* 將arg0數組,完全加在arg1的后面。
*
* @param arg0
* @param arg1
* @return
*/
private static int[] addAll(int[] arg0, int[] arg1) {
int[] arg = new int[arg0.length + arg1.length];
for (int i = 0; i < arg0.length + arg1.length; i++) {
if (i < arg0.length)
arg[i] = arg0[i];
else
arg[i] = arg1[i - arg0.length];
}
return arg;
}
/**
* 檢查括號是否正確使用。
*
* @param arg
* @return
*/
private static boolean CheckBracket(String arg) {
boolean bln = true;
if (SubStrCount(arg, "(") != SubStrCount(arg, ")")) {
bln = false;
}
if (bln) {
int[] lbracket = indexOf(arg, "(");
int[] rbracket = indexOf(arg, ")");
int length = lbracket.length;
// new ErrPrintArray(System.err).printArray(lbracket);
for (int i = 0; i < length; i++) {
bln &= lbracket[i] < rbracket[i];
}
}
return bln;
}
/**
* 檢查表達式,并返回最終合格得表達式結果,如果無法返回合格得結果,將拋出異常。
*
* @param arg
* @throws Exception
* @return
*/
private static String CheckTExpression(String arg) throws Exception {
// / 檢查符號前后是否存在空缺。
arg = Trim(arg);
// / 將%修改成/100的運算符。
arg = arg.replaceAll(TExpression.PERCENT, "/100");
if (!CheckBracket(arg))
throw new Exception("括號沒有匹配或者使用不當,請檢查!");
// / 在)(之間增加*符號。
arg = TrimBracket(arg);
// / 如果-號開頭,那么就在前面增加一個FU
if (arg.substring(0, 1).equals("-")) {
arg = TExpression.FU + arg.substring(1, arg.length());
}
// / 如果+號開頭,那么就去掉+號
if (arg.substring(0, 1).equals("-")) {
arg = arg.substring(1, arg.length());
}
// / 如果*/號開頭,那么前面加一個1
else if (arg.substring(0, 1).equals("*")
|| arg.substring(0, 1).equals("/")) {
arg = arg.substring(1, arg.length());
} else if (arg.substring(0, 1).equals("^")) {
throw new Exception("~符號不能用在公式開頭的位置!");
} else if (arg.substring(0, 1).equals("^")) {
throw new Exception("∧符號不能用在公式開頭的位置!");
}
return arg;
}
public static String Do(String expression, boolean showProcess)
throws Exception {
String testStr = expression;
/**
* 檢查字符串。
*/
String aa = null;
try {
aa = CheckTExpression(testStr);
} catch (Exception e) {
gLogger.error(e.getMessage(), e);
e.printStackTrace();
}
try {
String[] bb = TExpression.getVars(aa, DefaultVars);
int i = 0;
// 如果操作完的結果跟操作前相同,說明不需要繼續運算
// 增加i,避免死循環。
while (bb.length != 0 && i < 10000) {
aa = doOperate(aa);
if (showProcess) {
gLogger.info(aa);
}
bb = TExpression.getVars(aa, DefaultVars);
if (!isNaN(TrimAllBracket(aa))) {
aa = TrimAllBracket(aa);
break;
}
i++;
}
aa = TrimAllBracket(aa);
} catch (Exception e) {
gLogger.error(e.getMessage(), e);
e.printStackTrace();
}
return aa;
}
/**
* 對整個公式進行單步運算。
*
* @param arg
* @return
* @throws Exception
*/
private static String doOperate(String arg) throws Exception {
String leftRLT = "";
String rightRLT = "";
String rlt = arg;
int[] rkfs = TExpression.indexOf(rlt, new String[]
{ ")", });
int[] lkfs = TExpression.indexOf(rlt, new String[]
{ "(", });
// 找到第一個)符號。
// // 如果一個都沒有找到,那么直接對整個公式進行操作。
if (rkfs.length == 0) {
leftRLT = "";
rightRLT = "";
rlt = arg;
}
// // 否則,取()中間的內容,進行操作。
else {
int firstRkf = rkfs[0];
// System.out.println(arg.substring(firstRkf - 1, firstRkf + 2));
// 找到與第一個)符號對應的(
int containsLkf = lkfs[0];
for (int i = 1; i < lkfs.length; i++) {
if (lkfs[i] > firstRkf)
break;
else
containsLkf = lkfs[i];
}
// System.out.println(arg.substring(containsLkf - 1, containsLkf +
// 2));
// 取得中間的串,并取得兩端的串。
leftRLT = rlt.substring(0, containsLkf);
rightRLT = rlt.substring(firstRkf + 1, rlt.length());
rlt = rlt.substring(containsLkf + 1, firstRkf);
}
// System.out.println(rlt);
// 重新檢查語法
rlt = CheckTExpression(rlt);
String[] vars = getVars(rlt, DefaultVars);
String[] ops = getOperates(rlt, DefaultVars);
if (1 == 2) {
return null;
}
// 找到^~的運算
// // 如果存在^符號而且不存在~,或者存在^符號而且存在~符號并且^符號在~符號之前,那么就先運算^符號。
else if ((rlt.indexOf("^") != -1 && rlt.indexOf("~") == -1)
|| (rlt.indexOf("^") != -1 && rlt.indexOf("~") != -1 && rlt
.indexOf("^") < rlt.indexOf("~"))) {
int index = indexOf(ops, "^");
String op = TExpression.POWER;
rlt = doOperate1(rlt, vars[index], vars[index + 1], op);
rlt = "(" + rlt + ")";
}
// // 如果存在~符號而且不存在^,或者存在~符號而且存在^符號并且~符號在^符號之前,那么就先運算~符號。
else if ((rlt.indexOf("~") != -1 && rlt.indexOf("^") == -1)
|| (rlt.indexOf("~") != -1 && rlt.indexOf("^") != -1 && rlt
.indexOf("~") < rlt.indexOf("^"))) {
int index = indexOf(ops, "~");
if (vars[index + 1].equals("0"))
throw new Exception("【嚴重錯誤】:開方數不能為零");
String op = TExpression.SQRT;
rlt = doOperate1(rlt, vars[index], vars[index + 1], op);
rlt = "(" + rlt + ")";
}
// 如果沒有找到,那么找*/的運算
else if ((rlt.indexOf("*") != -1 && rlt.indexOf("/") == -1)
|| (rlt.indexOf("*") != -1 && rlt.indexOf("/") != -1 && rlt
.indexOf("*") < rlt.indexOf("/"))) {
int index = indexOf(ops, "*");
String op = TExpression.MULTIPLY;
rlt = doOperate1(rlt, vars[index], vars[index + 1], op);
rlt = "(" + rlt + ")";
}
// // 如果存在~符號而且不存在^,或者存在~符號而且存在^符號并且~符號在^符號之前,那么就先運算~符號。
else if ((rlt.indexOf("/") != -1 && rlt.indexOf("*") == -1)
|| (rlt.indexOf("/") != -1 && rlt.indexOf("*") != -1 && rlt
.indexOf("/") < rlt.indexOf("*"))) {
int index = indexOf(ops, "/");
if (vars[index + 1].equals("0"))
throw new Exception("【嚴重錯誤】:除數為零");
String op = TExpression.DIVIDE;
rlt = doOperate1(rlt, vars[index], vars[index + 1], op);
rlt = "(" + rlt + ")";
}
// 如果沒有找到,那么找+-運算
else if ((rlt.indexOf("+") != -1 && rlt.indexOf("-") == -1)
|| (rlt.indexOf("+") != -1 && rlt.indexOf("-") != -1 && rlt
.indexOf("+") < rlt.indexOf("-"))) {
int index = indexOf(ops, "+");
String op = TExpression.ADD;
rlt = doOperate1(rlt, vars[index], vars[index + 1], op);
rlt = "(" + rlt + ")";
}
// // 如果存在~符號而且不存在^,或者存在~符號而且存在^符號并且~符號在^符號之前,那么就先運算~符號。
else if ((rlt.indexOf("-") != -1 && rlt.indexOf("+") == -1)
|| (rlt.indexOf("-") != -1 && rlt.indexOf("+") != -1 && rlt
.indexOf("-") < rlt.indexOf("+"))) {
int index = indexOf(ops, "-");
String op = TExpression.DECREASE;
rlt = doOperate1(rlt, vars[index], vars[index + 1], op);
rlt = "(" + rlt + ")";
}
// // 如果什么符號都沒有找到,說明該串是個單變量的串,直接去掉兩端的括號,返回。
else {
rlt = TrimAllBracket(rlt);
}
// 把運算結果替換到適當的位置,然后返回。
return leftRLT + rlt + rightRLT;
}
/**
* 執行某個運算操作。
*
* @param vars
* @param ops
* @param op
*????????????如:"\\\\*"
* @return
* @throws Exception
*/
private static String doOperate1(String rlt, String var1, String var2,
String op) throws Exception {
String tmp = var1 + op + var2;
if (var1.indexOf(TExpression.FU) != -1) {
var1 = var1.replaceAll(TExpression.FU, "-");
}
if (!isNaN(var1) && !isNaN(var2)) {
// System.out.println(tmp);
rlt = rlt.replaceFirst(tmp, "" + operate(var1, var2, op));
}
rlt = "(" + rlt + ")";
return rlt;
}
/**
* 返回int數組中最小的一個。 假設數組中不存在相等的情況。
*
* @param arg
* @return
*/
private static int getMin(int[] arg, int fromIndex) throws Exception {
int i = arg[fromIndex];
for (int k = fromIndex + 1; k < arg.length; k++) {
if (arg[k] < i) {
i = arg[k];
} else if (arg[k] == i && arg[k] != Integer.MAX_value)
throw new Exception("數組中存在相等的值,無法進行取最小值的運算。");
}
return i;
}
/**
* 返回arg1中在arg2數組中存在的所有變量的順序組合。 如 (5*4+3) 返回 {*,+} ;
*
* @param arg1
* @param arg2
* @return
* @throws Exception
*/
private static String[] getOperates(String arg1, String[] arg2)
throws Exception {
int[] indexs = indexOf(arg1, arg2);
String[] ops = new String[indexs.length];
for (int i = 0; i < indexs.length; i++) {
ops[i] = arg1.substring(indexs[i], indexs[i] + 1);
}
return ops;
}
/**
* 返回arg1中在arg2數組中存在的所有變量兩端的變量的順序組合。 如 (5*4+3) 返回 {5,4,3} ;
*
* @param arg1
* @param arg2
* @return
* @throws Exception
*/
private static String[] getVars(String arg1, String[] arg2)
throws Exception {
// 去掉所有括號。
arg1 = arg1.replaceAll(TExpression.LBRACKET, "");
arg1 = arg1.replaceAll(TExpression.RBRACKET, "");
int[] indexs = indexOf(arg1, arg2);
// 如果沒有運算符,那么返回本身。
if (indexs.length == 0)
return new String[]
{ arg1 };
String[] vars = new String[indexs.length + 1];
for (int i = 0; i < indexs.length + 1; i++) {
if (i == 0)
vars[i] = arg1.substring(0, indexs[i]);
else if (i == indexs.length)
vars[i] = arg1.substring(indexs[i - 1] + 1, arg1.length());
else
vars[i] = arg1.substring(indexs[i - 1] + 1, indexs[i]);
}
return vars;
}
/**
* 取得arg0中arg1的所有索引的值。
*
* @param arg0
* @param arg1
* @return
*/
private static int[] indexOf(String arg0, String arg1) {
int i = 0;
int j = 0;
int[] intArr = new int[SubStrCount(arg0, arg1)];
while (arg0.indexOf(arg1, i) != -1) {
intArr[j] = arg0.indexOf(arg1, i);
i = intArr[j] + 1;
j++;
}
return intArr;
}
/**
* 取得arg0中arg1[]任意一個的所有索引的值。
*
* @param arg0
* @param arg1
* @return
*/
private static int[] indexOf(String arg0, String[] arg1) throws Exception {
int j = 0;
// 取得arg1中所有成員最近的位置。
int[] targets = new int[0];
for (int k = 0; k < arg1.length; k++) {
targets = addAll(targets, indexOf(arg0, arg1[k]));
}
Arrays.sort(targets);
int[] intArr = new int[targets.length];
while (j < intArr.length) {
// 取得最近的一個成員的位置。
int target = getMin(targets, j);
intArr[j] = target;
j++;
}
return intArr;
}
/**
* 返回字串數組中,相關值對應的索引。
*
* @param arg1
* @param arg2
* @return
*/
private static int indexOf(String[] arg1, String arg2) {
for (int i = 0; i < arg1.length; i++) {
if (arg2.equals(arg1[i]))
return i;
}
return -1;
}
/**
* 判斷是否為數字。
*
* @param arg
* @return
*/
private static boolean isNaN(String arg) {
if (arg == null || arg.length() == 0)
return true;
try {
Double.parseDouble(arg);
} catch (NumberFormatException e) {
return true;
}
return false;
}
public static void main(String[] args) {
String testStr = "((-1-2%*3^(4)~2/1)(7+8)-9)()";
testStr = "150*(200-600/40)*12+14*3-55+76+23/3+5+5";
// testStr = "150*(200-600/40)*12+14*3-55+76+23/3+5+5/0";
// System.err.println(testStr);
// System.out.println("gdasfds");
// System.out.println("gdasfds".replaceAll("k", ""));
// System.out.println(SubStrCount(testStr, "~"));
// System.out.println("gdass".indexOf("k"));
// new
// ErrPrintArray(System.err).printArray(TExpression.indexOf("fagaxa",
// "a"));
/**
* 檢驗括號是否正確。
*/
// boolean kk = CheckBracket(testStr);
// System.err.println(kk);
/**
* 獲得字符串中所有變量的順序組合。
*/
try {
// new ErrPrintArray(System.err).printArray(TExpression.getVars(aa,
// new String[] { "+", "-", "*", "/", "^", "~", }));
} catch (Exception e) {
e.printStackTrace();
}
/**
* 正式測試功能。
*/
try {
testStr = Do(testStr, true);
} catch (Exception e) {
e.printStackTrace();
}
System.err.println(testStr);
}
/**
* 直接運算得到結果。
*
* @param arg1
* @param arg2
* @param op
* @return
* @throws Exception
*/
private static double operate(String arg1, String arg2, String op)
throws Exception {
double a1 = Double.parseDouble(arg1);
double a2 = Double.parseDouble(arg2);
if (op.equals(TExpression.ADD)) {
return a1 + a2;
} else if (op.equals(TExpression.DECREASE)) {
return a1 - a2;
} else if (op.equals(TExpression.MULTIPLY)) {
return a1 * a2;
} else if (op.equals(TExpression.DIVIDE)) {
return a1 / a2;
} else if (op.equals(TExpression.SQRT)) {
return Math.pow(a1, 1 / a2);
} else if (op.equals(TExpression.POWER)) {
return Math.pow(a1, a2);
}
return 0d;
}
/**
* 返回arg0中包含的arg1的個數。
*
* @param arg0
* @param arg1
* @return
*/
private static int SubStrCount(String arg0, String arg1) {
int i = 0;
arg0 = Trim(arg0);
i = arg0.length();
arg1 = arg1.replaceAll("\\\\+", "\\\\" + ADD);
arg1 = arg1.replaceAll("\\\\-", "\\\\" + TExpression.DECREASE);
arg1 = arg1.replaceAll("\\\\*", "\\\\" + TExpression.MULTIPLY);
arg1 = arg1.replaceAll("\\\\^", "\\\\" + TExpression.POWER);
arg1 = arg1.replaceAll("\\\\(", "\\\\" + TExpression.LBRACKET);
arg1 = arg1.replaceAll("\\\\)", "\\\\" + TExpression.RBRACKET);
i = i - arg0.replaceAll(arg1, "").length();
return i;
}
/**
* 去除所有包含的空格。
*
* @param arg
* @return
*/
private static String Trim(String arg) {
String rlt = "";
rlt = arg.replaceAll(" ", "");
return rlt;
}
/**
* 去掉字串中的所有),(符號。
*
* @param arg
* @return
*/
private static String TrimAllBracket(String arg) {
String rlt = arg;
rlt = rlt.replaceAll("\\\\(", "");
rlt = rlt.replaceAll("\\\\)", "");
return rlt;
}
/**
* 去掉多余的()符號; 在)(之間增加*符號;
*
* @param arg
* @return
*/
private static String TrimBracket(String arg) {
String rlt = arg;
rlt = rlt.replaceAll("\\\\(\\\\)", "");
rlt = rlt.replaceAll("\\\\)\\\\(", "\\\\)\\\\*\\\\(");
return rlt;
}
}