字符串四则运算

解析字符串形式的表达式,求解四则运算
要求:
所有数字都是1-9的个位数
运算符包括+、-、*、/、(、和)
运算中间结果和最终结果为double类型

解题思路:
1、常规解法(利用栈):中缀转后缀,再求解;
2、分治法(利用正则匹配):
1)只有加减运算时,从左往右算即可
2)只有乘除运算时,从左往右算即可
3)既有乘除也有加减时,按照“+”和“-”拆分,把乘除运算表达式看做一个整体(当做一个操作数,通过情形 2)算出)
4)有括号时,先求解括号里面的表达式(按照情形 3)求解);
5)有括号嵌套时,从里向外循环求解(每一层都是情形 4));

import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Arithmetic {

    /**
    * 分治法
    **/
    private final String plusMinusRegex = "[\\+\\-]";

    // 9-(1+2*3)*4-(4+1)
    public double calcute(final String expression) throws Exception {
        StringBuilder expressionBuilder = new StringBuilder(expression);
        Pattern pattern = Pattern.compile("\\([\\d\\+\\-\\*/\\.]+\\)");
        Matcher matcher = pattern.matcher(expression);

        while(matcher.find()) {
            int start = matcher.start();
            int end = matcher.end();
            double r = calWithoutBracket(expressionBuilder.toString().substring(start+1,end-1));
            expressionBuilder.replace(start, end, String.valueOf(r));
            matcher = pattern.matcher(expressionBuilder.toString());
        }

        return calWithoutBracket(expressionBuilder.toString());
    }


    // 4+2*3-5*2
    public double calWithoutBracket(final String expression) throws Exception {

        double result = 0;

        String[] numberStrings = expression.split(plusMinusRegex);

        if(numberStrings[0].contains("*") || numberStrings[0].contains("/")) {
            result = multiplyAndDivide(numberStrings[0]);
        } else {
            result = Double.valueOf(numberStrings[0]);
        }

        int index = 1;
        Pattern pattern = Pattern.compile(plusMinusRegex);
        Matcher matcher = pattern.matcher(expression);
        while(matcher.find()) {
            String next = numberStrings[index];
            double nextNumber = (next.contains("*") || next.contains("/")) ? multiplyAndDivide(next) : Double.valueOf(next);

            String op = matcher.group();
            if(op.equals("+")) {
                result += nextNumber;
            } else if(op.equals("-")) {
                result -= nextNumber;
            }
            index++;
        }
        return result;
    }

    // 3.5/2.3*4.1
    public double multiplyAndDivide(String expression) {
        double result = 1;
        String pString = "[\\*\\/]";

        String[] numberStrings = expression.split(pString);
        if (numberStrings.length > 0) {
            result = Double.valueOf(numberStrings[0]);
        }

        int index = 1;
        Pattern pattern = Pattern.compile(pString);
        Matcher matcher = pattern.matcher(expression);

        while (matcher.find()) {
            String op = matcher.group();
            if (op.equals("*")) {
                result *= Double.valueOf(numberStrings[index]);
            } else if (op.equals("/")) {
                result /= Double.valueOf(numberStrings[index]);
            }
            index++;
        }
        return result;
    }

    // 1.5-2.8+3
    public double plusAndMinus(String expression) {

        double result = 0;
        String pString = "[\\+\\-]";

        String[] numberStrings = expression.split(pString);
        if (numberStrings.length > 0) {
            result = Double.valueOf(numberStrings[0]);
        }

        int index = 1;
        Pattern pattern = Pattern.compile(pString);
        Matcher matcher = pattern.matcher(expression);

        while (matcher.find()) {

            String op = matcher.group();
            if (op.equals("+")) {
                result += Double.valueOf(numberStrings[index]);
            } else if (op.equals("-")) {
                result -= Double.valueOf(numberStrings[index]);
            }
            index++;
        }
        return result;
    }

    public boolean isNumber(char ch) {
        return '0' <= ch && '9' >= ch;
    }

    public int charNumToInt(char num) {
        if (num < '0' || num > '9')
            throw new IllegalArgumentException(
                    "argument is not a char of decimal number");
        return num - '0';
    }
    /**
    * 中缀转后缀法
    **/
    public double calcute2(final String expression) {

        final String suffixExpression = getSuffixExpression(expression);

        Stack<String> stack = new Stack<String>();
        for(int i=0; i<suffixExpression.length(); i++) {
            char ch = suffixExpression.charAt(i);
            if(isNumber(ch)) {
                stack.push(String.valueOf(ch));
            } else {
                double rightOperand = Double.valueOf(stack.pop());
                double leftOperand = Double.valueOf(stack.pop());
                if(ch == '+') {
                    stack.push(String.valueOf(leftOperand + rightOperand));
                } else if(ch == '-') {
                    stack.push(String.valueOf(leftOperand - rightOperand));
                } else if(ch == '*') {
                    stack.push(String.valueOf(leftOperand * rightOperand));
                } else if(ch == '/') {
                    stack.push(String.valueOf(leftOperand / rightOperand));
                }
            }
        }
        return Double.valueOf(stack.pop());
    }

    public String getSuffixExpression(final String expression) {
        StringBuilder suffixExpression = new StringBuilder();
        Stack<Character> operatorStack = new Stack<Character>();
        for(int i = 0;i < expression.length(); i++) {
            char ch = expression.charAt(i);
            if(isNumber(ch)) {
                suffixExpression.append(ch);

            } else if(ch == '(') {
                operatorStack.push(ch);

            } else if(ch == ')') {
                char topOp;
                while((topOp = operatorStack.pop()) != '(') {
                    suffixExpression.append(topOp);
                }
            } else {
                if(!operatorStack.empty()) {
                    char topOp = operatorStack.peek();
                    while(getPriority(topOp) >= getPriority(ch)) {
                        suffixExpression.append(operatorStack.pop());
                        if(operatorStack.empty()) {
                            break;
                        }
                        topOp = operatorStack.peek();
                    }
                }
                operatorStack.push(ch);
            } 
        }
        while(!operatorStack.empty()) {
            suffixExpression.append(operatorStack.pop());
        }

        return suffixExpression.toString();
    }

    public int getPriority(char operator) {
        switch (operator) {
        case '+':
        case '-':
            return 1;
        case '*':
        case '/':
            return 2;
        default:
            return -1;
        }
    }
}

测试代码:

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import org.junit.Before;
import org.junit.Test;


public class ArithmeticTest {
    private Arithmetic arithmetic;

    @Before
    public void setUp() throws Exception {
        arithmetic = new Arithmetic();
    }
    @Test
    public void testIsNumber() throws Exception {
        assertTrue(arithmetic.isNumber('0'));
        assertTrue(arithmetic.isNumber('9'));
        assertTrue(arithmetic.isNumber('2'));
        assertFalse(arithmetic.isNumber('+'));
    }


    @Test
    public void testCharNumToInt() throws IllegalArgumentException{
        assertTrue(arithmetic.charNumToInt('2') == 2);
        try {
            arithmetic.charNumToInt('+');
            assertTrue(false);
        } catch (IllegalArgumentException e) {
            assertTrue(true);
        }
    }

    @Test
    public void testPlusAndMinus() throws Exception {
        assertTrue(arithmetic.plusAndMinus("8.5-3.2+2") == 7.3);
    }

    @Test
    public void testMultiplyAndDivide() throws Exception {
        assertTrue(arithmetic.multiplyAndDivide("4.0/2*4.1") == 8.2);
    }

    @Test
    public void testCalWithoutBracket() throws Exception {
        assertTrue(arithmetic.calWithoutBracket("4") == 4.0);
    }
    @Test
    public void testCalcute() throws Exception {
        assertTrue(arithmetic.calcute("(((5+2)*2)-(5+3))/2") == 3.0);

    }


    @Test
    public void testGetSuffixExpression() throws Exception {
        assertEquals(arithmetic.getSuffixExpression("9+7*4-(4+1)"),"974*+41+-");
    }

    @Test
    public void testCalcute2() throws Exception {
        assertTrue(arithmetic.calcute2("(2*(4+1))") == 10.0);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值