我们经常用到的表达式叫中缀式,如: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 +");
}
}