package cross.pauliuyou.calculator.base;
import java.math.BigDecimal;
import java.util.Vector;
/**
*
* @author 刘优
* @version 1.1
*
*
*
* */
public class Calculator {
private BigDecimal result = BigDecimal.ZERO;
private Vector express;
private static char[] ops = { '+', '-', '*', '/', '!', 's', 'p' };
private static char[] singleOps = { '-', '!', 's' };
private boolean isSingleOps(char c) {
for (int i = 0; i < singleOps.length; i++) {
if (c == singleOps[i]) {
return true;
}
}
return false;
}
private void alarm(String infor) throws CalculateException {
throw new CalculateException(infor);
}
private boolean syntax(String str) throws CalculateException {
char first = str.charAt(0);
if (isOperator(first) && first != '-') {
alarm("不能以运算符开头");
return false;
}
char last = str.charAt(str.length() - 1);
if (isOperator(last) && !isSingleOps(last) || last == '.' || last == '-') {
alarm("不能以运算符或点号结束");
return false;
}
int firstQuote = -1;
int leftCount = 0;
int rightCount = 0;
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (c == '(') {
if (firstQuote == -1) {
firstQuote = 1;
}
leftCount++;
if (i > 0) {
char leftChar = str.charAt(i - 1);
if (leftChar != '(' && !isOperator(leftChar)) {
alarm("左括号必须要跟一个运算符 ");
return false;
}
}
if (i > str.length() - 5) {
alarm("左括号用法错误, (2+3)");
return false;
}
char rightChar = str.charAt(i + 1);
if (rightChar != '(' && !isNumber(rightChar) && rightChar != '-') {
alarm("左括号后面要跟一个数 ");
return false;
}
if (rightChar == ')') {
alarm("左括号用法错误, (2+3)");
return false;
}
}
if (c == ')') {
if (firstQuote == -1) {
firstQuote = 2;
}
rightCount++;
if (i < str.length() - 2) {
char rightChar = str.charAt(i + 1);
if (rightChar != ')' && !isOperator(rightChar)) {
alarm("右括号后面要跟一个运算符 ");
return false;
}
}
if (i < 4) {
alarm("右括号用法错误, (2+3)");
return false;
}
char leftChar = str.charAt(i - 1);
if (leftChar != ')' && !isNumber(leftChar) && !isSingleOps(leftChar)) {
alarm("右括号前面必须是一个数 ");
return false;
}
if (leftChar == '(') {
alarm("左括号用法错误, (2+3)");
return false;
}
}
if (i < str.length() - 2) {
if (isOperator(c) && isOperator(str.charAt(i + 1)) && !isSingleOps(c)) {
alarm("运算符不能连续出现");
return false;
}
}
}
if (firstQuote == 2) {
alarm("左括号必须在前 ");
return false;
}
if (leftCount != rightCount) {
alarm("左右括号不匹配 ");
return false;
}
return true;
}
private void addStrToVector(Vector v,String str) {
if (str == null || str.length() == 0) return;
for (int i = 0; i < str.length(); i++) {
v.add(str.charAt(i));
}
}
private void addVector(String str) {
Stack<Integer> leftquotes = new Stack<Integer>();
Queue<Integer> rightquotes = new Queue<Integer>();
boolean over = false;
boolean found = false;
int begin = -1;
int end = -1;
while (end < str.length() - 1) {
over = false;
found = false;
int oldend = end;
for (int i = end + 1; i < str.length(); i++) {
char c = str.charAt(i);
if (c == '(' && !over) {
if (!found) {
begin = i;
found = true;
}
leftquotes.push(i);
}
if (c == ')') {
over = true;
rightquotes.add(i);
if (rightquotes.size() == leftquotes.size()) {
end = i;
break;
}
}
}
if (over) {
String strbefore = str.substring(oldend + 1,begin);
addStrToVector(express,strbefore);
int quotesNum = leftquotes.size();
Vector [] tmp = new Vector[quotesNum];
int before1 = -1;
int before2 = -1;
Vector before = null;
for (int x = 0; x < quotesNum; x++) {
tmp[x] = new Vector();
}
for (int x = 0; x < quotesNum; x++) {
Integer left = leftquotes.pop();
Integer right = rightquotes.get();
if (left != null && right != null) {
int now1 = left.intValue();
int now2 = right.intValue();
if (x == 0) {
String str3 = str.substring(now1 + 1,now2);
addStrToVector(tmp[x],str3);
}
else {
String str1 = str.substring(now1 + 1,before1);
String str2 = str.substring(before2 + 1,now2);
addStrToVector(tmp[x],str1);
tmp[x].add(before);
addStrToVector(tmp[x],str2);
if (x == quotesNum - 1) {
end = now2;
}
}
before1 = now1;
before2 = now2;
before = tmp[x];
}
}
express.add(tmp[quotesNum - 1]);
}
else {
for (int i = end + 1; i < str.length(); i++) {
char c = str.charAt(i);
if (c == '(') {
break;
}
express.add(c);
}
break;
}
for (int i = end + 1; i < str.length(); i++) {
char c = str.charAt(i);
if (c == '(') {
end = i - 1;
break;
}
express.add(c);
end = i;
}
}
}
private BigDecimal calExpress(Vector v) throws CalculateException {
Vector<BigDecimal> nums = new Vector<BigDecimal>();
Vector<Character> operators = new Vector<Character>();
String numStr = "";
for (int i = 0; i < v.size(); i++) {
Object o = v.get(i);
if (i == 0) {
if (o.getClass() == Character.class) {
if ((Character)o == '-') {
numStr += '-';
continue;
}
}
}
if (o.getClass() == Vector.class) {
nums.add(calExpress((Vector)o));
}
else {
char c = (Character)o;
if (isOperator(c)) {
if (numStr.length() > 0) {
try {
nums.add(new BigDecimal(numStr));
numStr = "";
}
catch (Exception e) {
throw new CalculateException("数字格式错误");
}
}
operators.add(c);
}
else {
numStr += c;
}
}
if (i == v.size() - 1) {
if (numStr.length() > 0)
try {
nums.add(new BigDecimal(numStr));
numStr = "";
}
catch (Exception e) {
throw new CalculateException("数字格式错误");
}
}
}
CalculateUnit unit = new CalculateUnit(nums,operators);
return unit.calculate();
}
public BigDecimal calculate(String expressStr) throws CalculateException {
if (express != null) {
express.clear();
}
express = new Vector();
if (syntax(expressStr)) {
addVector(expressStr);
try {
result = calExpress(express);
return result;
} catch (CalculateException e) {
alarm(e.getMessage());
}
}
return BigDecimal.ZERO;
}
private boolean isNumber(char c) {
if (c >= '0' && c <= '9') {
return true;
}
return false;
}
private boolean isOperator(char c) {
for (int x = 0; x < ops.length; x++) {
if (c == ops[x]) {
return true;
}
}
return false;
}
}
import java.math.BigDecimal;
import java.util.Vector;
/**
*
* @author 刘优
* @version 1.1
*
*
*
* */
public class Calculator {
private BigDecimal result = BigDecimal.ZERO;
private Vector express;
private static char[] ops = { '+', '-', '*', '/', '!', 's', 'p' };
private static char[] singleOps = { '-', '!', 's' };
private boolean isSingleOps(char c) {
for (int i = 0; i < singleOps.length; i++) {
if (c == singleOps[i]) {
return true;
}
}
return false;
}
private void alarm(String infor) throws CalculateException {
throw new CalculateException(infor);
}
private boolean syntax(String str) throws CalculateException {
char first = str.charAt(0);
if (isOperator(first) && first != '-') {
alarm("不能以运算符开头");
return false;
}
char last = str.charAt(str.length() - 1);
if (isOperator(last) && !isSingleOps(last) || last == '.' || last == '-') {
alarm("不能以运算符或点号结束");
return false;
}
int firstQuote = -1;
int leftCount = 0;
int rightCount = 0;
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (c == '(') {
if (firstQuote == -1) {
firstQuote = 1;
}
leftCount++;
if (i > 0) {
char leftChar = str.charAt(i - 1);
if (leftChar != '(' && !isOperator(leftChar)) {
alarm("左括号必须要跟一个运算符 ");
return false;
}
}
if (i > str.length() - 5) {
alarm("左括号用法错误, (2+3)");
return false;
}
char rightChar = str.charAt(i + 1);
if (rightChar != '(' && !isNumber(rightChar) && rightChar != '-') {
alarm("左括号后面要跟一个数 ");
return false;
}
if (rightChar == ')') {
alarm("左括号用法错误, (2+3)");
return false;
}
}
if (c == ')') {
if (firstQuote == -1) {
firstQuote = 2;
}
rightCount++;
if (i < str.length() - 2) {
char rightChar = str.charAt(i + 1);
if (rightChar != ')' && !isOperator(rightChar)) {
alarm("右括号后面要跟一个运算符 ");
return false;
}
}
if (i < 4) {
alarm("右括号用法错误, (2+3)");
return false;
}
char leftChar = str.charAt(i - 1);
if (leftChar != ')' && !isNumber(leftChar) && !isSingleOps(leftChar)) {
alarm("右括号前面必须是一个数 ");
return false;
}
if (leftChar == '(') {
alarm("左括号用法错误, (2+3)");
return false;
}
}
if (i < str.length() - 2) {
if (isOperator(c) && isOperator(str.charAt(i + 1)) && !isSingleOps(c)) {
alarm("运算符不能连续出现");
return false;
}
}
}
if (firstQuote == 2) {
alarm("左括号必须在前 ");
return false;
}
if (leftCount != rightCount) {
alarm("左右括号不匹配 ");
return false;
}
return true;
}
private void addStrToVector(Vector v,String str) {
if (str == null || str.length() == 0) return;
for (int i = 0; i < str.length(); i++) {
v.add(str.charAt(i));
}
}
private void addVector(String str) {
Stack<Integer> leftquotes = new Stack<Integer>();
Queue<Integer> rightquotes = new Queue<Integer>();
boolean over = false;
boolean found = false;
int begin = -1;
int end = -1;
while (end < str.length() - 1) {
over = false;
found = false;
int oldend = end;
for (int i = end + 1; i < str.length(); i++) {
char c = str.charAt(i);
if (c == '(' && !over) {
if (!found) {
begin = i;
found = true;
}
leftquotes.push(i);
}
if (c == ')') {
over = true;
rightquotes.add(i);
if (rightquotes.size() == leftquotes.size()) {
end = i;
break;
}
}
}
if (over) {
String strbefore = str.substring(oldend + 1,begin);
addStrToVector(express,strbefore);
int quotesNum = leftquotes.size();
Vector [] tmp = new Vector[quotesNum];
int before1 = -1;
int before2 = -1;
Vector before = null;
for (int x = 0; x < quotesNum; x++) {
tmp[x] = new Vector();
}
for (int x = 0; x < quotesNum; x++) {
Integer left = leftquotes.pop();
Integer right = rightquotes.get();
if (left != null && right != null) {
int now1 = left.intValue();
int now2 = right.intValue();
if (x == 0) {
String str3 = str.substring(now1 + 1,now2);
addStrToVector(tmp[x],str3);
}
else {
String str1 = str.substring(now1 + 1,before1);
String str2 = str.substring(before2 + 1,now2);
addStrToVector(tmp[x],str1);
tmp[x].add(before);
addStrToVector(tmp[x],str2);
if (x == quotesNum - 1) {
end = now2;
}
}
before1 = now1;
before2 = now2;
before = tmp[x];
}
}
express.add(tmp[quotesNum - 1]);
}
else {
for (int i = end + 1; i < str.length(); i++) {
char c = str.charAt(i);
if (c == '(') {
break;
}
express.add(c);
}
break;
}
for (int i = end + 1; i < str.length(); i++) {
char c = str.charAt(i);
if (c == '(') {
end = i - 1;
break;
}
express.add(c);
end = i;
}
}
}
private BigDecimal calExpress(Vector v) throws CalculateException {
Vector<BigDecimal> nums = new Vector<BigDecimal>();
Vector<Character> operators = new Vector<Character>();
String numStr = "";
for (int i = 0; i < v.size(); i++) {
Object o = v.get(i);
if (i == 0) {
if (o.getClass() == Character.class) {
if ((Character)o == '-') {
numStr += '-';
continue;
}
}
}
if (o.getClass() == Vector.class) {
nums.add(calExpress((Vector)o));
}
else {
char c = (Character)o;
if (isOperator(c)) {
if (numStr.length() > 0) {
try {
nums.add(new BigDecimal(numStr));
numStr = "";
}
catch (Exception e) {
throw new CalculateException("数字格式错误");
}
}
operators.add(c);
}
else {
numStr += c;
}
}
if (i == v.size() - 1) {
if (numStr.length() > 0)
try {
nums.add(new BigDecimal(numStr));
numStr = "";
}
catch (Exception e) {
throw new CalculateException("数字格式错误");
}
}
}
CalculateUnit unit = new CalculateUnit(nums,operators);
return unit.calculate();
}
public BigDecimal calculate(String expressStr) throws CalculateException {
if (express != null) {
express.clear();
}
express = new Vector();
if (syntax(expressStr)) {
addVector(expressStr);
try {
result = calExpress(express);
return result;
} catch (CalculateException e) {
alarm(e.getMessage());
}
}
return BigDecimal.ZERO;
}
private boolean isNumber(char c) {
if (c >= '0' && c <= '9') {
return true;
}
return false;
}
private boolean isOperator(char c) {
for (int x = 0; x < ops.length; x++) {
if (c == ops[x]) {
return true;
}
}
return false;
}
}