最近一个题目需要自己计算一个字符串数学表达式的值, 所以大体研究了一下. 自己使用java实现
功能有:
1, 支持有小数点的计算
2, 支持带负号的计算
3, 支持带括号的计算
4, 支持参数计算
代码如下:
package on0911;
import java.util.Stack;
/**
* 计算简单数学表达式的值
* @author Administrator
*
*/
public class Expression {
private Stack<Double> data = new Stack<Double>();
private Stack<Operator> operatorStack = new Stack<Operator>();
private String exp;
enum Op{
JIA('+'), JIAN('-'), CHENG('*'), CHU('/');
private char value;
Op(char value) {
this.value = value;
}
public char getValue() {
return value;
}
}
public Expression(String exp) {
this.exp = exp.replace(" ", "");
}
public static void main(String[] args) {
String expression = "-30 + 36* 2 / 4 - 1 * - 0.4 ";
System.out.println("表达式结果是:" + new Expression(expression).doC());
}
/**
* 计算表达式的值
* @return
*/
public double doC() {
inStack();
/*当符号栈不为空的时候进行计算*/
while (operatorStack.size() > 0) {
Double re = ontStep(data, operatorStack);
data.push(re);
}
return data.pop();//返回最后结果
}
/**
* 扫描表达式, 根据条件将表达式的内容进行简单计算, 然后入栈
*/
public void inStack() {
if (exp.endsWith("+") || exp.endsWith("-") || exp.endsWith("*") || exp.endsWith("/")) {
throw new RuntimeException("表达式有误!不能以运算符结尾");
}
/*循环所有字符, 判断后进行操作*/
for (int i = 0; i < exp.length();) {
char c = exp.charAt(i++);//取得第一个字符
/*在是数字值的情况下, 或者是负号的情况下, 继续搜索后续的字符*/
if ((c <= '9' && c >= '0') || c == '.' || (i == 1 && c == '-')
|| (i > 1 && isOperator(exp.charAt(i - 2)))) {
String temp = c + "";
/*所有后续字符, 组成规定的数值*/
for (; i < exp.length();) {
char c2 = exp.charAt(i++);
if ((c2 <= '9' && c2 >= '0') || c2 == '.') {
temp += c2;
} else {
break;//判断跳出条件时, 漏过一个字符, 这是因为最后一个字符应该是数字, 所以如果不是数字就不管他
}
}
/*如果不是最后一个数值的话, 游标前移一位, 重新读取刚才漏过的字符*/
if (i != exp.length()) {
i--;
}
Double num = Double.parseDouble(temp);
data.push(num);//将数据压入数据栈
} else {
if (isOperator(c)){
Operator op = new Operator(c);
if (operatorStack.size() == 0) {
operatorStack.push(op);//运算符栈在空的时候直接入栈
} else {
Operator stackPop = operatorStack.pop();
//比较运算符栈栈顶运算符和当前运算符的优先级
//1, 如果大于栈顶运算符的优先级, 就直接入栈.
//2, 小于或者等于的话, 就先计算数据栈和运算符栈的一次, 然后将结果压入数据栈.
// 然后将当前运算符压入运算符栈
if (op.getPriority() > stackPop.getPriority()) {
operatorStack.push(stackPop);
operatorStack.push(op);
} else {
operatorStack.push(stackPop);
Double re = ontStep(data, operatorStack);//计算一次
data.push(re);//压结果入栈
operatorStack.push(op);//当前运算符入栈
}
}
} else {
throw new RuntimeException(c + "符号错误");
}
}
}
}
private boolean isOperator(char c) {
if (Op.JIA.getValue() == c || Op.JIAN.getValue() == c || Op.CHENG.getValue() == c || Op.CHU.getValue() == c) {
return true;
}
return false;
}
/**
* 将数据栈的数据提取两个和运算符栈的一个运算符进行计算, 且返回结果
* @param data2
* @param operatorStack2
* @return
*/
private Double ontStep(Stack<Double> data2, Stack<Operator> operatorStack2) {
Double re = 0d;
Double next = data2.pop();
Double pre = data2.pop();
Operator o = operatorStack.pop();
re = cal(pre, o, next);//计算数据
return re;
}
/**
* 计算得到值
* @param pre
* @param o
* @param next
* @return
*/
private Double cal(Double pre, Operator o, Double next) {
if (o == null) {
throw new RuntimeException("空操作符");
}
char cc = o.getOp();
if (cc == Op.JIA.getValue()) {
return new Double(pre + next);
}
if (cc == Op.JIAN.getValue()) {
return new Double(pre - next);
}
if (cc == Op.CHENG.getValue()) {
return new Double(pre * next);
}
if (cc == Op.CHU.getValue()) {
return new Double(pre / next);
}
throw new RuntimeException("错误的运算符!");
}
/**
* 自定义的操作符类
* @author Administrator
*
*/
class Operator {
char op;
int priority;
public Operator(char op) {
this.op = op;
switch (op) {
case '+': priority = 5;break;
case '-': priority = 5;break;
case '*': priority = 6;break;
case '/': priority = 6;break;
default: throw new RuntimeException("错误的操作符");
}
}
public char getOp() {
return op;
}
public void setOp(char op) {
this.op = op;
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
}
}
package on0911;
/**
* 计算带括号的复杂表达式的值
* @author Administrator
*
*/
public class ComplexExpression {
/**
* 计算给定字符串的表达式值
* @param str
* @return
*/
public double doD(String str) {
String exp = str.replace(" ", "");//替换空字符
int flag = 0;//标志括号位
StringBuilder exp2 = new StringBuilder();//储存去除括号后的表达式
/*扫描给定表达式字符串, 进行判断然后响应操作*/
for (int i = 0; i < exp.length();) {
char c = exp.charAt(i++);
//碰到时左括号的时候, 标志位自加, 然后将此括号内的字符串进行计算得到数值后放到exp2中
if (c == '(') {
flag++;
StringBuilder sb = new StringBuilder();//此括号内的字符串
for (; i < exp.length();) {
char c2 = exp.charAt(i++);
sb.append(c2 + "");//添加字符
//左括号自加, 右括号自减
if (c2 == '(') {
flag++;
} else if (c2 == ')') {
flag--;
}
/*碰到右括号时, 如果标志位确认是当前左括号的互补括号, 就进行递归计算此字符串的值*/
if (c2 == ')' && flag == 0) {
String temp = sb.substring(0, sb.length() - 1);
temp = getValue(temp);//递归计算括号内的值
exp2.append(temp);//将值添加到exp2字符串中
break;
}
}
} else {
exp2.append(c);
}
}
//System.out.println(exp2.toString());
return new Expression(exp2.toString()).doC();//返回计算exp2值的数值
}
/**
* 递归计算给定字符串的值
* @param temp
* @return
*/
private String getValue(String temp) {
temp = temp.replace(" ", "");
if (!temp.contains("(")) {
return new Expression(temp).doC() + "";//当不含有括号的时候,直接返回计算值
}
return doD(temp) + "";//有括号的时候就返回计算括号内得到的值
}
public static void main(String[] args) {
//String str = "3 *- (1 - 2 / 4) + ( 1 + (2 - 3)) + 2";
//System.out.println("答案是:" + new ComplexExpression().getValue(str));
varTest();
}
public static void varTest() {
int A = 2, B = 34;
String str = "3 *- (A - 2 / 4) + ( 1 + (2 - B)) + 2";
str = str.replace("A", A + "");
str = str.replace("B", B + "");
System.out.println("答案是:" + new ComplexExpression().getValue(str));
}
}
分享到:
评论