Java 버 전 Eval

6462 단어 자바
다른 언어 에 있 는 Eval 함 수 를 사용 해 봤 는데 eval 이라는 것 을 알 고 있 었 지만, 자바 표준 패키지 에는 eval 방법 이 제공 되 지 않 았 습 니 다.어제 프로그램 을 쓸 때 이 기능 을 사용 하여 손 쉽게 썼 습 니 다. 물론 인터넷 에 있 는 다른 사람의 버 전 을 참고 하여 감사 하 게 생각 합 니 다.다른 것 은 더 이상 말 하지 않 고 바로 코드 를 올 립 니 다.
package com.winson.calc;

import java.util.ArrayList;
import java.util.Stack;

public class WinsonEval {

	private final static String ERR_NOT_END_VALID = "The last character of your expression MUST be '#'!";
	private final static String ERR_PARENTHESE_NOT_PAIR = "'(' & ')' should be used in pair!";
	private final static String ERR_CHAR_NOT_SUPPORT = "Not supported character";
	private final static String ERR_OPERATION_NOT_SUPPORTED = "Not supported operation";
	private final static String ERR_OPERATOR_NOT_VALID = " doesn't support double data!";
	private final static String ERR_UNKNOWN = "An unknown error!";
	
	private static boolean flag_double;

	/*
	 * expression must be end with #
	 */
	public static String eval(String expression) {

		ArrayList list;
		try {
			list = toSuffixSequence(expression);
			return calculate(list);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	
	public static boolean isResultDouble(){
		return flag_double;
	}

	private static String calculate(ArrayList list) throws Exception {
		Stack stack = new Stack();
		for (String s : list) {
			if (isOperator(s)) {
				String d1 = stack.pop();
				String d2 = stack.pop();
				String res = doCalc(d2, d1, s);
				stack.push(res);
			} else
				stack.push(s);
		}
		
		if (stack.size() == 1)
			return stack.pop();
		else
			throw new Exception(ERR_UNKNOWN);
	}

	private static String doCalc(String d1, String d2, String oper) throws Exception {
		if (oper != null && oper.length() > 1)
			throw new Exception(ERR_OPERATION_NOT_SUPPORTED + ":'" + oper + "'");

		flag_double = isDoubleNeeded(d1, d2, oper);

		switch (oper.charAt(0)) {
		case '+':
			if (flag_double)
				return Double.toString(Double.parseDouble(d1)
						+ Double.parseDouble(d2));
			else
				return Integer.toString(Integer.parseInt(d1)
						+ Integer.parseInt(d2));
		case '-':
			if (flag_double)
				return Double.toString(Double.parseDouble(d1)
						- Double.parseDouble(d2));
			else
				return Integer.toString(Integer.parseInt(d1)
						- Integer.parseInt(d2));
		case '*':
			if (flag_double)
				return Double.toString(Double.parseDouble(d1)
						* Double.parseDouble(d2));
			else
				return Integer.toString(Integer.parseInt(d1)
						* Integer.parseInt(d2));
		case '/':
			if (flag_double)
				return Double.toString(Double.parseDouble(d1)
						/ Double.parseDouble(d2));
			else
				return Integer.toString(Integer.parseInt(d1)
						/ Integer.parseInt(d2));
		case '%':
			if (flag_double)
				throw new Exception("'%' " + ERR_OPERATOR_NOT_VALID);
			else
				return Integer.toString(Integer.parseInt(d1)
						+ Integer.parseInt(d2));
		default:
			throw new Exception(ERR_OPERATION_NOT_SUPPORTED + ":'" + oper + "'");
		}
	}

	private static boolean isDoubleNeeded(String d1, String d2, String oper) {
		if (d1.contains(".") || d2.contains("."))
			return true;
		if (oper != null && oper.equals("/")) {
			int left = Integer.parseInt(d1) % Integer.parseInt(d2);
			if (left != 0)
				return true;
		}
		return false;
	}

	private static boolean isOperator(String str) {
		if (str != null
				&& (str.equals("+") || str.equals("-") || str.equals("*")
						|| str.equals("/") || str.equals("%")))
			return true;
		return false;
	}

	private static ArrayList toSuffixSequence(String expression)
			throws Exception {

		if (!expression.endsWith("#"))
			throw new Exception(ERR_NOT_END_VALID);

		ArrayList list = new ArrayList();
		Stack stack = new Stack();
		stack.push("#");
		char last, ch;
		StringBuffer sb = null;
		for (int i = 0; i < expression.length(); i++) {
			ch = expression.charAt(i);
			switch (ch) {

			case '+':
			case '-':
			case '*':
			case '/':
			case '%':
				last = stack.peek().charAt(0);
				if (last != '(' && priority(last) >= priority(ch))
					list.add(stack.pop());
				stack.push("" + ch);
				break;
			case '(':
				stack.push("(");
				break;
			case ')':
				while (!stack.isEmpty() && stack.peek().charAt(0) != '(')
					list.add(stack.pop());
				if (stack.isEmpty() || stack.size() == 1)
					throw new Exception(ERR_PARENTHESE_NOT_PAIR);
				stack.pop();
				break;
			case '#':
				while (stack.size() > 1 && stack.peek().charAt(0) != '(')
					list.add(stack.pop());
				if (stack.size() > 1)
					throw new Exception(ERR_PARENTHESE_NOT_PAIR);
				break;
			default:
				if (Character.isDigit(ch) || '.' == ch) {
					sb = new StringBuffer();
					sb.append(ch);
					while (Character.isDigit(expression.charAt(i+1)) || expression.charAt(i+1) == '.')
						sb.append(expression.charAt(++i));
					
					list.add(sb.toString());
					break;
				} else
					throw new Exception(ERR_CHAR_NOT_SUPPORT + ":'" + ch + "'");

			}
		}
		return list;
	}

	private static int priority(char ch) {
		switch (ch) {
		case '+':
		case '-':
			return 1;
		case '*':
		case '/':
		case '%':
			return 2;
		case '#':
			return 0;
		default:
			return 0;
		}
	}

	public static void main(String[] args) {
		String expression = "2+-7#";
		try {
			System.out.println(WinsonEval.toSuffixSequence(expression).toString());
			System.out.println(WinsonEval.eval(expression));
		} catch (Exception e) {
			e.printStackTrace();
		}
		
//		System.out.println(Character.getType('.'));
//		System.out.println(Character.getType('1'));
	}
}

두 가지 설명: 1. 결 과 를 String 형식 으로 되 돌려 줍 니 다. 마지막 결과 가 int 형 이면 소수점 이 없고 반대로 double 형식 으로 표 시 됩 니 다.결과 유형 을 얻 기 위해 isResultDouble () 방법 을 동시에 갖 추 었 다.
2. 음수 표현 을 직접적 으로 지원 하지 않 고 (0 - n) 의 형식 으로 명시 적 으로 바 꿔 야 한다.
bug 가 있 으 면 메 시 지 를 환영 합 니 다.

좋은 웹페이지 즐겨찾기