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;
}
}