文字计算器
对输入的加减乘除等四则运算得出结果,是否考虑负数,小数等(难度:★★★★)由自己决定
例如:输入:1+2*2-4 输出为1
输入:1+2+3+4 输出为10
输入:1+2/5-4*2 输出为-6.6
在做这个题的时候,也看到网上有很多关于这个四则运算的算法实现。但是我还是想自己思考一下。我的想法其实很直接。分析思路如下:
1、四则运算优先级: 乘 除 加 减
2、按照优先级将输入的字符串进行划分计算
(1)第一优先级的乘法先通过字符串进行切分,分别获取*号前面部分和后面部分。然后进行计算。最近将计算结果6替换2*3的位置、8替换4*2的位置。
(2)第二优先级除法,也按照第一优先级的方式进行计算和字符串拼接。
(3)第三优先级加法,也按照第一优先级的方式进行计算和字符串拼接。
(4)第四优先级减法,也按照第一优先级的方式进行计算和字符串拼接。
经过四次运算,也就算成了整个计算。如果有扩展功能,比如添加大括号什么的,只是添加一层皮,多一层包装而已。真正的计算为:1、获取具体优先级表达式。2、计算。3、替换位置,形成子字符串。
具体实现代码如下:
package com.yxie.test.arithmetic;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.yxie.test.arithmetic.constant.ArithmeticEnum;
import com.yxie.test.arithmetic.pojo.ReplaceArithmeticPojo;
import com.yxie.test.arithmetic.util.ArithmeticUtil;
public class ArithmeticTest {
private static final Integer PRECISION = 20;
private static final RoundingMode ROUNDINGMODE = RoundingMode.HALF_UP;
/***
* 获取计算前面部分的数字
*
* @return
*/
public Map<Integer, String> getPreIndexStr(String subArithmeticStr) {
Map<Integer, String> numIndexMap = new HashMap<Integer, String>();
Integer tempIndex = 0;
StringBuffer tempSb = new StringBuffer();
for (int i = subArithmeticStr.length() - 1; i >= 0; i--) {
if (ArithmeticEnum.MULTIPLICATION.getValue().equals(Character.toString(subArithmeticStr.charAt(i)))) {
tempIndex = i;
break;
} else if (ArithmeticEnum.DIVISION.getValue().equals(Character.toString(subArithmeticStr.charAt(i)))) {
tempIndex = i;
break;
} else if (ArithmeticEnum.ADD.getValue().equals(Character.toString(subArithmeticStr.charAt(i)))) {
tempIndex = i;
break;
} else if (ArithmeticEnum.REDUCE.getValue().equals(Character.toString(subArithmeticStr.charAt(i)))) {
tempIndex = i;
break;
} else {
tempSb.insert(0, subArithmeticStr.charAt(i));// 前面拼接
}
}
numIndexMap.put(tempIndex, tempSb.toString());
return numIndexMap;
}
/***
* 获取计算后面部分最近的数字
*
* @return
*/
public Map<Integer, String> getAfterIndexStr(String subArithmeticStr) {
Map<Integer, String> numIndexMap = new HashMap<Integer, String>();
Integer tempIndex = 0;
StringBuffer tempSb = new StringBuffer();
for (int i = 0; i < subArithmeticStr.length(); i++) {
if (ArithmeticEnum.MULTIPLICATION.getValue().equals(Character.toString(subArithmeticStr.charAt(i)))) {
tempIndex = i;
break;
} else if (ArithmeticEnum.DIVISION.getValue().equals(Character.toString(subArithmeticStr.charAt(i)))) {
tempIndex = i;
break;
} else if (ArithmeticEnum.ADD.getValue().equals(Character.toString(subArithmeticStr.charAt(i)))) {
tempIndex = i;
break;
} else if (ArithmeticEnum.REDUCE.getValue().equals(Character.toString(subArithmeticStr.charAt(i)))) {
tempIndex = i;
break;
} else {
tempSb.append(subArithmeticStr.charAt(i));
}
}
numIndexMap.put(tempIndex, tempSb.toString());
return numIndexMap;
}
/**
* 按精确度计算结果
*
* @param numString
* @param precision
* @param roundingMode
* @return
*/
public static BigDecimal getBigDecimal(String numString, int precision, RoundingMode roundingMode) {
String precisionFlag = "0";
if (numString == null || numString.equals("")) {
precisionFlag = "0.00";
} else {
precisionFlag = numString;
}
BigDecimal bigDecimal = new BigDecimal(precisionFlag);
bigDecimal.setScale(precision, roundingMode);
return bigDecimal;
}
public StringBuffer calculateVal(StringBuffer inputArithmeticStr, String arithmeticEnumVal) {
List<ReplaceArithmeticPojo> repList = new ArrayList<ReplaceArithmeticPojo>();
ReplaceArithmeticPojo tempRepl = null;
boolean addTempReplBool = false;
for (int i = 0; i < inputArithmeticStr.length(); i++) {
if (arithmeticEnumVal.equals(Character.toString(inputArithmeticStr.charAt(i)))) {
// System.out.println("in:" + i);
Map<Integer, String> preNumIndexMap = getPreIndexStr(inputArithmeticStr.substring(0, i));// 前面部分
Integer preStrIndex = (Integer) preNumIndexMap.keySet().iterator().next();
String preStr = (String) preNumIndexMap.get(preStrIndex);
Map<Integer, String> afterNumIndexMap = getAfterIndexStr(inputArithmeticStr.substring(i + 1,
inputArithmeticStr.length()));// 后面部分
Integer afterStrIndex = (Integer) afterNumIndexMap.keySet().iterator().next();
String afterStr = (String) afterNumIndexMap.get(afterStrIndex);
// 判断传入参数是否慢主条件
if (arithmeticEnumVal.equals(ArithmeticEnum.DIVISION.getValue())) {
if (!ArithmeticUtil.isDouble(preStr) || !ArithmeticUtil.isNumber(afterStr)) {
return new StringBuffer().append("ERROR:" + preStr + ";" + afterStr);
}
} else if (!ArithmeticUtil.isDouble(preStr) || !ArithmeticUtil.isDouble(afterStr)) {
return new StringBuffer().append("ERROR:" + preStr + ";" + afterStr);
}
if (preStrIndex != 0) {
preStrIndex = preStrIndex + 1;
}
if (afterStrIndex == 0) {
afterStrIndex = inputArithmeticStr.length();
} else {
afterStrIndex = i + 1 + afterStrIndex;
}
BigDecimal tempNumber = null;
if (tempRepl != null) {
ReplaceArithmeticPojo addRepl = new ReplaceArithmeticPojo();
if (tempRepl.getEndIndex() >= preStrIndex) {// 开始时间和上一个tempRepl.getStartIndex()存在交集,也就是连续的计算如:2*4*5
tempNumber = calBigDecimal(arithmeticEnumVal, tempRepl.getCalVal(), afterStr);
addRepl.setCalVal(tempNumber.toString());
addRepl.setStartIndex(tempRepl.getStartIndex());
addRepl.setEndIndex(afterStrIndex);
tempRepl = addRepl;
addTempReplBool = true;
} else {
tempNumber = calBigDecimal(arithmeticEnumVal, preStr, afterStr);
if (addTempReplBool) {
repList.add(tempRepl);
tempRepl = null;
addTempReplBool = false;
}
addRepl.setCalVal(tempNumber.toString());
addRepl.setStartIndex(preStrIndex);
addRepl.setEndIndex(afterStrIndex);
tempRepl = addRepl;
addTempReplBool = true;
}
} else {// 第一次
tempNumber = calBigDecimal(arithmeticEnumVal, preStr, afterStr);
tempRepl = new ReplaceArithmeticPojo();
tempRepl.setCalVal(tempNumber.toString());
tempRepl.setStartIndex(preStrIndex);
tempRepl.setEndIndex(afterStrIndex);
addTempReplBool = true;
}
// System.out.println("preStr:" + preStr + ";afterStr:" + afterStr);
// System.out.println("preStrIndex:" + preStrIndex + ";afterStrIndex:" + afterStrIndex);
// System.out.println("preSubString:" + inputArithmeticStr.substring(preStrIndex, afterStrIndex));
}
}
if (addTempReplBool) {
repList.add(tempRepl);
}
// System.out.println("======================begin repList==================");
// for (int j = 0; j < repList.size(); j++) {
// ReplaceArithmeticPojo eveRepPojo = repList.get(j);
// System.out.println("getCalVal:" + eveRepPojo.getCalVal() + ";getStartIndex:" + eveRepPojo.getStartIndex()
// + ";getEndIndex:" + eveRepPojo.getEndIndex());
// }
// System.out.println("======================end repList==================");
// 开始进行替换
StringBuffer replaceReturnSB = new StringBuffer();
int tempEndIndex = -1;
for (int j = 0; j < repList.size(); j++) {
ReplaceArithmeticPojo eveRepPojo = repList.get(j);
if (j == 0) {
replaceReturnSB.append(inputArithmeticStr.substring(0, eveRepPojo.getStartIndex())).append(eveRepPojo.getCalVal());
tempEndIndex = eveRepPojo.getEndIndex();
} else {
replaceReturnSB.append(inputArithmeticStr.substring(tempEndIndex, eveRepPojo.getStartIndex())).append(eveRepPojo.getCalVal());
tempEndIndex = eveRepPojo.getEndIndex();
}
if (j == repList.size() - 1) {
replaceReturnSB.append(inputArithmeticStr.substring(eveRepPojo.getEndIndex(),
inputArithmeticStr.length()));
}
}
return replaceReturnSB;
}
private BigDecimal calBigDecimal(String arithmeticEnumVal, String preStr, String afterStr) {
BigDecimal preBigDecimal = getBigDecimal(preStr, PRECISION, ROUNDINGMODE);
BigDecimal afterBigDecimal = getBigDecimal(afterStr, PRECISION, ROUNDINGMODE);
BigDecimal tempNumber = getBigDecimal("", PRECISION, ROUNDINGMODE);
if (arithmeticEnumVal.equals(ArithmeticEnum.ADD.getValue())) {
tempNumber = preBigDecimal.add(afterBigDecimal);
} else if (arithmeticEnumVal.equals(ArithmeticEnum.REDUCE.getValue())) {
tempNumber = preBigDecimal.subtract(afterBigDecimal);
} else if (arithmeticEnumVal.equals(ArithmeticEnum.MULTIPLICATION.getValue())) {
tempNumber = preBigDecimal.multiply(afterBigDecimal);
} else if (arithmeticEnumVal.equals(ArithmeticEnum.DIVISION.getValue())) {
tempNumber = preBigDecimal.divide(afterBigDecimal, PRECISION, ROUNDINGMODE);
}
return tempNumber;
}
private void arithmetic(StringBuffer inputArithmeticStr) {
StringBuffer sbBak = new StringBuffer();
sbBak.append(inputArithmeticStr);// 用于备份提示信息用。
// 存在乘法
if (inputArithmeticStr.indexOf(ArithmeticEnum.MULTIPLICATION.getValue()) != -1) {
inputArithmeticStr = calculateVal(inputArithmeticStr, ArithmeticEnum.MULTIPLICATION.getValue());
if (inputArithmeticStr.toString().indexOf("ERROR") != -1) {
System.out.println("输入的表达式(" + sbBak + ")有问题:" + inputArithmeticStr);
System.exit(0);
}
// System.out.println("MULTIPLICATION inputArithmeticStr:" + inputArithmeticStr);
// System.out.println("MULTIPLICATION:" + indexList);
}
// 存在除法
if (inputArithmeticStr.indexOf(ArithmeticEnum.DIVISION.getValue()) != -1) {
inputArithmeticStr = calculateVal(inputArithmeticStr, ArithmeticEnum.DIVISION.getValue());
if (inputArithmeticStr.toString().indexOf("ERROR") != -1) {
System.out.println("输入的表达式(" + sbBak + ")有问题:" + inputArithmeticStr);
System.exit(0);
}
// System.out.println("DIVISION inputArithmeticStr:" + inputArithmeticStr);
// System.out.println("DIVISION");
}
// 存在加法
if (inputArithmeticStr.indexOf(ArithmeticEnum.ADD.getValue()) != -1) {
inputArithmeticStr = calculateVal(inputArithmeticStr, ArithmeticEnum.ADD.getValue());
if (inputArithmeticStr.toString().indexOf("ERROR") != -1) {
System.out.println("输入的表达式(" + sbBak + ")有问题:" + inputArithmeticStr);
System.exit(0);
}
// System.out.println("ADD inputArithmeticStr:" + inputArithmeticStr);
// System.out.println("ADD");
}
// 存在减法
if (inputArithmeticStr.indexOf(ArithmeticEnum.REDUCE.getValue()) != -1) {
inputArithmeticStr = calculateVal(inputArithmeticStr, ArithmeticEnum.REDUCE.getValue());
if (inputArithmeticStr.toString().indexOf("ERROR") != -1) {
System.out.println("输入的表达式(" + sbBak + ")有问题:" + inputArithmeticStr);
System.exit(0);
}
// System.out.println("REDUCE inputArithmeticStr:" + inputArithmeticStr);
// System.out.println("REDUCE");
}
System.out.println("======================begin 执行结果===================================");
System.out.println(inputArithmeticStr);
System.out.println("======================end 执行结果===================================");
}
/**
* @param args
*/
public static void main(String[] args) {
// 1/3/2+4/3+45/2+2*2*2/2*2*2*2*2*2*2*2*2*2+1/3/2+4/3+45/2+2*2*2*2*2*2*2*2*2*2*2*2*2
StringBuffer inputArithmeticStr = new StringBuffer().append("1/3/2+4/3-45/2+2*2*2/2*2*2*2*2*2*2*2*2*2");
System.out.println("inputArithmeticStr:" + inputArithmeticStr);
ArithmeticTest arithmeticTest1 = new ArithmeticTest();
arithmeticTest1.arithmetic(inputArithmeticStr);
}
}
package com.yxie.test.arithmetic.pojo;
public class ReplaceArithmeticPojo {
private Integer startIndex;
private Integer endIndex;
private String calVal;
public Integer getStartIndex() {
return startIndex;
}
public void setStartIndex(Integer startIndex) {
this.startIndex = startIndex;
}
public Integer getEndIndex() {
return endIndex;
}
public void setEndIndex(Integer endIndex) {
this.endIndex = endIndex;
}
public String getCalVal() {
return calVal;
}
public void setCalVal(String calVal) {
this.calVal = calVal;
}
}
import java.math.BigDecimal;
public class ArithmeticUtil {
/***
* 只能是正整数
*
* @param str
* @return
*/
public static boolean isNumber(String str) {
return str.matches("\\d+");
}
/***
* 判断是否慢主数字的条件。包括整数,负数,double类型。
*
* @param str
* @return
*/
public static boolean isDouble(String str) {
return str.matches("-?\\d+\\.?\\d*");
}
/**
* 提供精确的加法运算。
*
* @param v1 被加数
* @param v2 加数
* @return 两个参数的和
*/
public static double addReturnDouble(String v1, String v2) {
BigDecimal decimal1 = new BigDecimal(v1);
BigDecimal decimal2 = new BigDecimal(v2);
return decimal1.add(decimal2).doubleValue();
}
/**
* 提供精确的加法运算。
*
* @param v1 被加数
* @param v2 加数
* @return 两个参数的和
*/
public static int addReturnInt(String v1, String v2) {
BigDecimal decimal1 = new BigDecimal(v1);
BigDecimal decimal2 = new BigDecimal(v2);
return decimal1.add(decimal2).intValue();
}
/**
* 提供精确的减法运算。
*
* @param v1 被减数
* @param v2 减数
* @return 两个参数的差
*/
public static double subReturnDouble(String v1, String v2) {
BigDecimal decimal1 = new BigDecimal(v1);
BigDecimal decimal2 = new BigDecimal(v2);
return decimal1.subtract(decimal2).doubleValue();
}
/**
* 提供精确的减法运算。
*
* @param v1 被减数
* @param v2 减数
* @return 两个参数的差
*/
public static int subReturnInt(String v1, String v2) {
BigDecimal decimal1 = new BigDecimal(v1);
BigDecimal decimal2 = new BigDecimal(v2);
return decimal1.subtract(decimal2).intValue();
}
/**
* 提供精确的乘法运算。
*
* @param v1 被乘数
* @param v2 乘数
* @return 两个参数的积
*/
public static double mulReturnDouble(String v1, String v2) {
BigDecimal decimal1 = new BigDecimal(v1);
BigDecimal decimal2 = new BigDecimal(v2);
return decimal1.multiply(decimal2).doubleValue();
}
/**
* 提供精确的乘法运算。
*
* @param v1 被乘数
* @param v2 乘数
* @return 两个参数的积
*/
public static int mulReturnInt(String v1, String v2) {
BigDecimal decimal1 = new BigDecimal(v1);
BigDecimal decimal2 = new BigDecimal(v2);
return decimal1.multiply(decimal2).intValue();
}
/**
* 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到 小数点以后10位,以后的数字四舍五入。
*
* @param v1 被除数
* @param v2 除数
* @return 两个参数的商
*/
public static double devReturnDouble(String v1, String v2) {
BigDecimal decimal1 = new BigDecimal(v1);
BigDecimal decimal2 = new BigDecimal(v2);
return decimal1.divide(decimal2, 60, BigDecimal.ROUND_HALF_UP).doubleValue();// 保证大数据不报错
}
}
//单元测试的类
package com.yxie.test.arithmetic;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import com.yxie.test.arithmetic.constant.ArithmeticEnum;
import com.yxie.test.arithmetic.pojo.ReplaceArithmeticPojo;
import com.yxie.test.arithmetic.util.ArithmeticUtil;
public class ArithmeticJunit {
@Test
public void testIndexFlag() {
String subArithmeticStr = "1+233.5";
StringBuffer tempSb = new StringBuffer();
for (int i = subArithmeticStr.length() - 1; i > 0; i--) {
if (ArithmeticEnum.MULTIPLICATION.getValue().equals(Character.toString(subArithmeticStr.charAt(i)))) {
break;
} else if (ArithmeticEnum.DIVISION.getValue().equals(Character.toString(subArithmeticStr.charAt(i)))) {
break;
} else if (ArithmeticEnum.ADD.getValue().equals(Character.toString(subArithmeticStr.charAt(i)))) {
break;
} else if (ArithmeticEnum.REDUCE.getValue().equals(Character.toString(subArithmeticStr.charAt(i)))) {
break;
} else {
tempSb.insert(0, subArithmeticStr.charAt(i));
}
}
System.out.println("tempSb:" + tempSb);
}
@Test
public void testIsNumber() {
System.out.println("23".matches("\\d+"));
System.out.println("2311111111".matches("\\d+"));
System.out.println("23".matches("-?\\d+\\d*"));
System.out.println("-23.34".matches("-?\\d+\\d*"));
}
@Test
public void testIsDouble() {
System.out.println("-23".matches("-?\\d+\\.?\\d*"));
System.out.println("23".matches("-?\\d+\\.?\\d*"));
System.out.println("-23.34".matches("-?\\d+\\.?\\d*"));
}
@Test
public void testBigDecimal() {
BigDecimal realCJCommi1 = new BigDecimal("-34");
BigDecimal realCJCommi2 = new BigDecimal("-34");
System.out.println(realCJCommi1.add(realCJCommi2));
System.out.println(-34 + (-34));
System.out.println(add(-34, -34));
}
public static double add(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.add(b2).doubleValue();
}
@Test
public void testList() {
List<ReplaceArithmeticPojo> repList = new ArrayList<ReplaceArithmeticPojo>();
ReplaceArithmeticPojo tempRepl = new ReplaceArithmeticPojo();
tempRepl.setCalVal("23");
repList.add(tempRepl);
tempRepl = null;
for (ReplaceArithmeticPojo rep : repList) {
System.out.println(rep.getCalVal());
}
}
/***
* 获取计算后面部分最近的数字
*
* @return
*/
@Test
public void testGetAfterIndexStr() {
String subArithmeticStr = "2.121+233.5";
StringBuffer tempSb = new StringBuffer();
for (int i = 0; i < subArithmeticStr.length(); i++) {
if (ArithmeticEnum.MULTIPLICATION.getValue().equals(Character.toString(subArithmeticStr.charAt(i)))) {
break;
} else if (ArithmeticEnum.DIVISION.getValue().equals(Character.toString(subArithmeticStr.charAt(i)))) {
break;
} else if (ArithmeticEnum.ADD.getValue().equals(Character.toString(subArithmeticStr.charAt(i)))) {
break;
} else if (ArithmeticEnum.REDUCE.getValue().equals(Character.toString(subArithmeticStr.charAt(i)))) {
break;
} else {
tempSb.append(subArithmeticStr.charAt(i));
}
}
System.out.println("tempSb:" + tempSb);
}
@Test
public void test() {
StringBuffer a = new StringBuffer("aaaa");
a.insert(0, "bb");
System.out.println(a);
}
@Test
public void testBigDecimalArithmeticUtil() {
System.out.println(ArithmeticUtil.addReturnDouble("-1.4", "3"));
System.out.println(ArithmeticUtil.addReturnDouble("1.4", "3"));
System.out.println(ArithmeticUtil.addReturnDouble("3.4444", "3"));
System.out.println(ArithmeticUtil.addReturnInt("3", "3"));
System.out.println(ArithmeticUtil.subReturnDouble("3", "3"));
System.out.println(ArithmeticUtil.subReturnInt("3", "3"));
System.out.println(ArithmeticUtil.mulReturnDouble("3", "3"));
System.out.println(ArithmeticUtil.mulReturnInt("3", "3"));
System.out.println("devReturnDouble:" + ArithmeticUtil.devReturnDouble("3", "3.34433434343443343434"));
}
public static void main(String[] args) {
System.out.println("0.8970394978269958370069547891983".length());
}
}
具体网上实现自己去搜吧,很多,呵呵呵。