我们经常用到的表达式叫中缀式,如:1+2,a+b*c;
还有另外一种表达式叫后缀式,叫逆波兰式。
原理我就不赘述了,网上很多介绍。
现在写了个Java中缀式转后缀式的工具类,现分享源码如下:
操作符常量接口:
/** * <pre> * 操作符常量接口:主要为了保存常量 * * @author dobuy * 修改时间: 2013-5-22 * </pre> */ public interface Operators { /** * 操作符优先级:高 */ int HIGH_PRIORITY = 10; /** * 操作符优先级:中 */ int MIDIUM_PRIORITY = 5; /** * 操作符优先级:低 */ int LOW_PRIORITY = 1; /** * 错误(或未知)的操作符 */ int ERROR_PRIORITY = -1; char OPEN_BRACKET = '('; char CLOSE_BRACKET = ')'; char ADD = '+'; char SUBRACTION = '-'; char MULTIPLITICATION = '*'; char DIVISION = '/'; char COMPLIMENT = '%'; char SPACE = ' '; char ZERO = '0'; char NINE = '9'; char LOWER_CASE_A = 'a'; char LOWER_CASE_Z = 'z'; char UPPER_CASE_A = 'A'; char UPPER_CASE_Z = 'Z'; String EMPTY = ""; /** * 表达式中待过滤的字符(正则表达式中用到,需转义),下同; */ String OPEN_SQUARE_BRACKET = "\\["; String CLOSE_SQUARE_BRACKET = "\\]"; String OPEN_CURLY_BRACE = "\\{"; String CLOSE_CURLY_BRACE = "\\}"; }
表达式工具类
import java.util.HashMap; import java.util.Map; /** * <pre> * 操作符处理工具类 * * @author dobuy * 修改时间: 2013-5-22 * </pre> */ public final class OperatorUtils { /** * 保存所有操作符(Key)及优先级(Value) */ private static final Map<Character, Integer> priorities; private OperatorUtils() { } /** * 类加载时初始化 */ static { priorities = new HashMap<Character, Integer>(); getPriorities().put(Operators.OPEN_BRACKET, Operators.HIGH_PRIORITY); getPriorities().put(Operators.MULTIPLITICATION, Operators.MIDIUM_PRIORITY); getPriorities().put(Operators.DIVISION, Operators.MIDIUM_PRIORITY); getPriorities().put(Operators.COMPLIMENT, Operators.MIDIUM_PRIORITY); getPriorities().put(Operators.ADD, Operators.LOW_PRIORITY); getPriorities().put(Operators.SUBRACTION, Operators.LOW_PRIORITY); } /** * <pre> * 字符是否是操作符(除了字母和数字都是操作符) * * @param ch * @return * @author dobuy * 修改时间: 2013-5-22 */ public static boolean isOperator(char ch) { return !isCharacter(ch) && !isNumber(ch); } /** * * <pre> * ch1的优先级是否不高于ch2 * * @param ch1 * @param ch2 * @return * </pre> */ public static boolean isLowerOfPriority(char ch1, char ch2) { int priority1 = getPriority(ch1); int priority2 = getPriority(ch2); return priority1 <= priority2; } /** * * <pre> * 是否字母 * @param ch * @return */ private static boolean isCharacter(char ch) { return (ch >= Operators.LOWER_CASE_A && ch <= Operators.LOWER_CASE_Z) || (ch >= Operators.UPPER_CASE_A && ch <= Operators.UPPER_CASE_Z); } /** * * <pre> * 字符是否数字 * * @param ch * @return */ private static boolean isNumber(char ch) { return ch <= Operators.NINE && ch >= Operators.ZERO; } /** * * <pre> * 获取操作符的优先级 * * @param ch * @return */ private static int getPriority(char ch) { if (getPriorities().containsKey(ch)) { return getPriorities().get(ch); } return Operators.ERROR_PRIORITY; } /** * 获取 priorities * * @return 返回 priorities */ private static Map<Character, Integer> getPriorities() { return priorities; } }
表达式处理工具类:
import java.util.Stack; /** * <pre> * 中缀表达式变后缀表达式工具类 * * @author dobuy * 修改时间: 2013-5-22 * </pre> */ public final class SuffixExpressionUtils { /** * 保存表达式中操作符的栈 */ private static final Stack<Character> operators = new Stack<Character>(); /** * 表达式的输出结果 */ private static final StringBuilder result = new StringBuilder(); private static char lastElement; /** * 私有化构造方法,避免被实例化 <默认构造函数> */ private SuffixExpressionUtils() { } /** * * <pre> * 把中缀式变后缀表达式 * * @param exp * @return * </pre> */ public static String getSuffixExp(String exp) { if (exp == null || exp.length() == 0) { return exp; } init(); // 所有{}[]全部替换成对应的小括号 exp = exp.replaceAll(Operators.OPEN_CURLY_BRACE, Operators.OPEN_BRACKET + Operators.EMPTY); exp = exp.replaceAll(Operators.CLOSE_CURLY_BRACE, Operators.CLOSE_BRACKET + Operators.EMPTY); exp = exp.replaceAll(Operators.OPEN_SQUARE_BRACKET, Operators.OPEN_BRACKET + Operators.EMPTY); exp = exp.replaceAll(Operators.CLOSE_SQUARE_BRACKET, Operators.CLOSE_BRACKET + Operators.EMPTY); // 去掉表达式中所有的" " exp = exp.replaceAll(Operators.SPACE + Operators.EMPTY, Operators.EMPTY); char[] characters = exp.toCharArray(); for (char ch : characters) { // 如果不是操作符,直接添加 if (!OperatorUtils.isOperator(ch)) { addCharToResult(ch); } // 如果是')',则从操作符栈中压出操作符,直到'('为止 else if (ch == Operators.CLOSE_BRACKET) { popUntilOpenBracket(); } // 如果是'('或者操作符的优先级高于栈顶元素(如果栈顶时'('时,做特殊处理) else if (ch == Operators.OPEN_BRACKET || !isLowerThanTop(ch)) { operators.push(ch); } // 如果优先级不高于栈顶元素时,栈顶元素出栈,直到栈顶元素优先级高于待入栈元素,并把待入栈元素入栈 else { popUntilLowerTop(ch); } lastElement = ch; } popAllOperators(); return result.toString().trim(); } /** * * <pre> * 由于定义的是静态方法,执行前,先清空操作符栈中的内容,避免受上一次的干扰 * * </pre> */ private static void init() { operators.clear(); result.delete(0, result.length()); } /** * * <pre> * 碰到')'时,从操作符栈中弹出操作符,直到'('为止 * * </pre> */ private static void popUntilOpenBracket() { char lastElement = operators.lastElement(); while (lastElement != Operators.OPEN_BRACKET) { addCharToResult(operators.pop()); lastElement = operators.lastElement(); } // 最后再弹出'(' operators.pop(); } /** * * <pre> * 待入栈元素优先级是否不高于栈顶元素,栈为空时,为高于 * * @param ch * @return * </pre> */ private static boolean isLowerThanTop(char ch) { // 操作符栈为空或为'('时,操作符需要直接入栈 if (operators.isEmpty() || operators.lastElement() == Operators.OPEN_BRACKET) { return false; } char topChar = operators.lastElement(); return OperatorUtils.isLowerOfPriority(ch, topChar); } /** * <pre> * 当待入栈的操作符优先级不高于栈顶时,栈顶元素出栈,直至栈顶元素低于待入栈元素,然后再把待入栈元素入栈 * * @param ch * </pre> */ private static void popUntilLowerTop(char ch) { while (isLowerThanTop(ch)) { addCharToResult(operators.pop()); } operators.push(ch); } /** * * <pre> * 把解析好的字符加入输出结果中 * * @param ch * </pre> */ private static void addCharToResult(char ch) { // 结果不为空时,同时不连续为非操作符时,加空格后再加字符 if (OperatorUtils.isOperator(ch) || OperatorUtils.isOperator(lastElement)) { result.append(Operators.SPACE); } result.append(ch); } /** * <pre> * 表达式解析完毕,依次从栈顶弹出操作符 * * </pre> */ private static void popAllOperators() { while (!operators.isEmpty()) { addCharToResult(operators.pop()); } } }单元测试类:
import static org.junit.Assert.assertEquals; import org.junit.Test; /** * <pre> * <一句话功能简述> * * </pre> */ public class SuffixExpressionUtilsTest { @Test public void testGetSuffixExp01() { assertEquals(SuffixExpressionUtils.getSuffixExp(null), null); } @Test public void testGetSuffixExp02() { String result = SuffixExpressionUtils.getSuffixExp("1+2*3"); assertEquals(result, "1 2 3 * +"); } @Test public void testGetSuffixExp02_1() { String result = SuffixExpressionUtils.getSuffixExp("1*2-3"); assertEquals(result, "1 2 * 3 -"); } @Test public void testGetSuffixExp03() { String result = SuffixExpressionUtils.getSuffixExp("(7-(1+2)/5)*3+8"); assertEquals(result, "7 1 2 + 5 / - 3 * 8 +"); } @Test public void testGetSuffixExp04() { String result = SuffixExpressionUtils.getSuffixExp("(70-(11+22)/55)*63+897"); assertEquals(result, "70 11 22 + 55 / - 63 * 897 +"); } @Test public void testGetSuffixExp05() { String result = SuffixExpressionUtils.getSuffixExp("{[70-(11+22)]/55}*63+897"); assertEquals(result, "70 11 22 + - 55 / 63 * 897 +"); } @Test public void testGetSuffixExp06() { String result = SuffixExpressionUtils.getSuffixExp("{[70-(a+22)]/c}*63+897"); assertEquals(result, "70 a 22 + - c / 63 * 897 +"); } }