本次测试内容为结对开发,我和蒲煜凡组队进行开发,对于结对开发我们都没什么经验,初步分工为我编写计算类,由他编写页面,然后我进行测试,蒲煜凡进行指导。

通过这次结对开发,锻炼了我们合作的能力,美中不足是两人异地,配合起来有些僵硬

Text.java

package size;

 

import java.math.BigDecimal;

import java.util.HashMap;

import java.util.Map;

import java.util.Scanner;

import java.util.Stack;

import java.util.regex.Matcher;

import java.util.regex.Pattern;

 

public class Text {

 

//字符合法检验正则表达式

private static final Pattern EXPRESSION_PATTERN = Pattern.compile("[0-9\\.+-/*()= ]+");

 

//运算符优先级map

private static final Map<String, Integer> OPT_PRIORITY_MAP = new HashMap<String,Integer>(){

private static final long serialVersionUID = 4633502127458385800L;

 

{

put("(",0);

put("+",2);

put("-",2);

put("*",3);

put("/",3);

put(")",7);

put("=",20);

}

};

 

/**

 * 运算执行类

 * @param expression 算数表达式

 * @return

 */

public static String Calc(String expression) {

//非空校验

if (expression == null || "".equals(expression.trim())) {

throw new IllegalArgumentException("表达式不能为空!");

}

 

//表达式字符合法校验

Matcher matcher = EXPRESSION_PATTERN.matcher(expression);

if (!matcher.matches()) {

throw new IllegalArgumentException("表达式含有非法字符!");

}

 

Stack<String> optStack = new Stack<>();//运算符栈

Stack<BigDecimal> numStack = new Stack<>();//数值栈

StringBuilder curNumBuilder = new StringBuilder();//正在读取的可变字符串

 

//逐个读取字符,执行计算操作

for (int i = 0; i < expression.length(); i++) {

char c = expression.charAt(i);

if (c != ' ') {//丢弃空白字符

if ((c >= '0' && c <='9') || c == '.') {

curNumBuilder.append(c);

}

else {

if (curNumBuilder.length() > 0) 

{

numStack.push(new BigDecimal(curNumBuilder.toString()));

curNumBuilder.delete(0, curNumBuilder.length());

}

 

String curOpt = String.valueOf(c);//当前运算符

if (optStack.empty())//运算符栈顶位空直接入栈

{

optStack.push(curOpt);   

} 

else {

if (curOpt.equals("(")) {           //左括号直接入栈

optStack.push(curOpt);

} 

else if (curOpt.equals(")"))          //右括号执行括号内的运算

{

insideCalc(optStack, numStack, true);

} 

    else if (curOpt.equals("=")) {//等号进行剩余运算,运算结束

insideCalc(optStack, numStack, false);

return String.valueOf(numStack.pop().doubleValue());

}

  

 

 

 

 

 

 

 

 

    else {

compareAndCalc(optStack, numStack, curOpt);//加减乘除判断后进行运算

}

}

}

}

}

 

//若字符串不以等号结尾

if (curNumBuilder.length() > 0) {

numStack.push(new BigDecimal(curNumBuilder.toString()));

}

insideCalc(optStack, numStack, false);

return String.valueOf(numStack.pop().doubleValue());

}

 

/**

 * 遇到括号或等号时的运算

 * @param optStack 运算符栈

 * @param numStack 数值栈

 * @param b true为括号,false为等号

 */

private static void insideCalc(Stack<String> optStack, Stack<BigDecimal> numStack,

boolean b) {

String opt = optStack.pop();

BigDecimal num2 = numStack.pop();

BigDecimal num1 = numStack.pop();

BigDecimal bigDecimal = floatingPointCalc(opt, num1, num2);

 

//结果入栈

numStack.push(bigDecimal);

 

if (b) {//右括号情况

if ("(".equals(optStack.peek())) {//遇到左括号停止运算并将其弹出

optStack.pop();

} else {

insideCalc(optStack, numStack, b);

}

} else {//等号情况,递归运算直到栈空

if (!optStack.empty()) {

insideCalc(optStack, numStack, b);

}

}

 

}

 

/**

 * 二元运算,支持高精度

 * @param opt

 * @param num1

 * @param num2

 * @return

 */

private static BigDecimal floatingPointCalc(String opt, BigDecimal num1,

BigDecimal num2) {

 

BigDecimal result = new BigDecimal(0);

switch (opt) {

case "+":

result = num1.add(num2);

break;

case "-":

result = num1.subtract(num2);

break;

case "*":

result = num1.multiply(num2);

break;

case "/":

//BigDecimal的divide方法第一个参数表示除数,第二个表示小数点后位数,第三个表示舍入模式

result = num1.divide(num2, 10, BigDecimal.ROUND_HALF_DOWN);

break;

}

return result;

}

 

/**

 * 判断当前运算符与栈顶运算符优先级并进行计算

 * @param optStack 运算符栈

 * @param numStack 数值栈

 * @param curOpt 当前运算符

 */

private static void compareAndCalc(Stack<String> optStack, Stack<BigDecimal> numStack, 

String curOpt) {

 

//比较当前运算符与栈顶运算符的优先级

String peekOpt = optStack.peek();

int priority = getPriority(peekOpt, curOpt);

if (priority == -|| priority == 0) {

//当前运算符比栈顶运算符低或同级,取栈顶运算符执行运算

String opt = optStack.pop();

BigDecimal num2 = numStack.pop();

BigDecimal num1 = numStack.pop();

BigDecimal bigDecimal = floatingPointCalc(opt, num1, num2);//计算

 

numStack.push(bigDecimal);//结果入栈

 

//判断栈空与否,非空还要再进行递归判断

if (optStack.empty()) {

optStack.push(curOpt);

} else {

compareAndCalc(optStack, numStack, curOpt);

}

} else {

//当前优先级高,入栈

optStack.push(curOpt);

}

}

 

/**

 * 判断运算符优先级

 * @param peekOpt

 * @param curOpt

 * @return 1表示同级,1表示第二个运算符级别高,-1表示第一个运算符级别高

 */

private static int getPriority(String peekOpt, String curOpt) {

int result = OPT_PRIORITY_MAP.get(curOpt) - OPT_PRIORITY_MAP.get(peekOpt);

return result;

}

 

/**

 * 解决负数问题

 * @param expression

 * @return

 */

private static String updateExpression(String expression) {

 

//解决首位负数

if (expression.trim().charAt(0) == '-') {

expression = "0" + expression;

}

//解决括号中的负数

expression = expression.replace("(-", "(0-");

return expression;

}

 

 

public static void main(String[] args) {

String expression = "";

Scanner in = new Scanner(System.in);

System.out.println("请输入要计算的表达式:");

expression = in.nextLine();

expression = updateExpression(expression);

System.out.println(Calc(expression));

}

}