【发布时间】:2015-12-15 21:30:11
【问题描述】:
我遇到了一个要求将中缀表达式解析为后缀的问题。但首先我需要检查中缀表达式是否正确。该怎么做?
在输入中,都是有效的:
- 操作数:所有字母大写和小写('a'..'z'、'A'..'Z')和数字 (0...9)。
- 括号。
- 运算符:接受下面显示的优先级表中的所有以下运算符:
我见过的一个可能的解决方案是先从中缀解析到后缀,然后检查后缀表达式是否有效。
我尝试使用以下算法解析中缀后缀
1) 从左到右读取表达式中的每个字符并创建一个空堆栈
2) 如果当前字符是放在输出上的操作数
3) 如果当前字符是运算符并且堆栈为空;将其推入堆栈。
4) 如果当前字符是一个操作符并且栈不为空;而堆栈顶部的运算符具有更高的优先级,然后当前运算符将堆栈顶部放在输出上并将其弹出;最后将当前字符压入堆栈;
5) 如果当前字符为 '(' 则将其推入堆栈。
6) 如果当前字符是')',则出栈并输出;直到找到一个'('。7)在输入结束时;如果堆栈不为空;弹出所有元素并将其放在输出上。
但是这种算法在这种情况下不起作用:“(ab+c)/2(e+a)”。因为它将构造一个有效的后缀表达式。但是这个表达式不是一个有效的中缀表达式。
这是我的代码:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.Stack;
public class Main {
public static boolean isOperand(char c) {
return ('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
}
public static int getThePrecedence(char c){
if(c == '^')
return 6;
if(c == '*' || c == '/')
return 5;
if(c == '-' || c == '+')
return 4;
if(c == '>' || c == '<' || c == '=' || c == '#')
return 3;
if(c == '.')
return 2;
if(c == '|')
return 1;
return 0;
}
public static boolean checkParenthesis(String s){
int stack = 0;
for (int i = 0; i < s.length(); ++i) {
char c = s.charAt(i);
if(c == '(')
++stack;
else if(c == ')'){
--stack;
if(stack < 0)
return false;
}
}
return stack == 0;
}
public static String parseInfixToPostfix(String s) {
StringBuilder out = new StringBuilder("");
Stack<Character> stack = new Stack<>();
for (int i = 0; i < s.length(); ++i) {
char c = s.charAt(i);
if (isOperand(c)) {
out.append(c);
continue;
}
if (c == '(') {
stack.add(c);
continue;
}
if (c == ')') {
char ch = stack.pop();
//create a temporary stringbuilder to check if the expression has an empty parenthesis ()
StringBuilder temp = new StringBuilder("");
while (ch != '(') {
temp.append(ch);
ch = stack.pop();
}
if(temp.length() == 0) //empty parenthesis
return ""; //will be invalidated by the postfix checker
out.append(temp.toString());
continue;
}
//here are only operators
if(stack.empty()){
stack.push(c);
}
else{
while(!stack.empty() && ( getThePrecedence(stack.peek()) >= getThePrecedence(c) ))
out.append(stack.pop());
stack.push(c);
}
}
while(!stack.empty())
out.append(stack.pop());
return out.toString();
}
public static boolean postFixValidate(String s){
if(s.equals(""))
return false;
int stack = 0;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if(c == '(' || c == ')')
continue;
if(isOperand(c)){
++stack;
}
else {
stack -= 2;
if(stack < 0)
return false;
++stack;
}
}
return stack == 1;
}
public static boolean lexicalAnalysis(String s){
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if(isOperand(c) == false && getThePrecedence(c) == 0 && c != '(' && c != ')')
return false;
}
return true;
}
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
PrintStream out = new PrintStream(System.out);
while (true) {
String s = in.readLine();
if (lexicalAnalysis(s)) {
if(checkParenthesis(s)){
String postfix = parseInfixToPostfix(s);
if(postFixValidate(postfix)){
System.out.println(postfix);
}
else{
out.println("Syntax Error!");
}
}
else{
out.println("Syntax Error!");
}
} else {
out.println("Lexical Error!");
}
}
}
}
【问题讨论】:
-
也许你最好使用编译器-编译器来解析
Yacc或bison之类的表达式。