In my Java program file, I am trying to write a method that will evaluate a postfix expression.
I am also trying to write an eval() method for my Expression class that evaluates an infix expression by first converting it to postfix and then evaluating the postfix.
For example, in main, if I write: eval("1 + 2 * 3") I should get 7.
However, in my program, when I write this, all it returns is -1.
Can anyone help me pinpoint the error in my code, either in the evalPostfix() or eval() methods?
public class Expression {
private static final String SPACE = " ";
private static final String PLUS = "+";
private static final String MINUS = "-";
public static int rank(String operator) {
switch (operator) {
case "^": //5
return 3;
case "*":
case "/":
return 2;
case PLUS:
case MINUS: //2
return 1;
case "()": //6
return 0;
default:
return -1;
}
}
public static boolean isOperator(String token) { //4
if (rank(token) > 0){
return true;
}
return false;
}
public static int applyOperator(String operator,int op1,int op2){ //7
switch (operator) {
case PLUS:
return op1+op2;
case MINUS:
return op1-op2;
case "*":
return op1*op2;
case "/":
return op1/op2;
case "^":
return (int) Math.pow( (double) op1, (double) op2); //9
default:
return -1;
}
}
public static String toPostfix(String infixExpr) {
StringBuilder output = new StringBuilder();
Stack<String> operators = new ArrayStack<>();
Stack<Character> s = new ArrayStack<Character>(); //6
for (int i = 0; i < infixExpr.length(); i++){
if(infixExpr.charAt(i) == '(');
s.push('(');
if(infixExpr.charAt(i) == ')' && !operators.isEmpty()){
s.pop();
if(s.isEmpty())
output.append(s.pop());
if(s.pop() != '(')
operators.pop();
}
}
for (String token: infixExpr.split("\\s+")) {
if (isOperator(token)) { // operator //4
// pop equal or higher precedence
while (!operators.isEmpty() &&
rank(operators.peek()) >= rank(token)) {
output.append(operators.pop() + SPACE);
}
operators.push(token);
} else { // operand
output.append(token + SPACE);
}
}
while (!operators.isEmpty()) {
output.append(operators.pop() + SPACE);
}
return output.toString();
}
public static int evalPostfix(String infixExpr) { //8
Stack <String> s = new ArrayStack<String>();
String operand = null;
for(int i = 0; i < infixExpr.length(); i++) {
if (Character.isDigit(infixExpr.charAt(i)))
s.push(infixExpr.charAt(i) + "");
else {
if (s.size() > 1) {
int value1 = Integer.parseInt(s.pop());
int value2 = Integer.parseInt(s.pop());
s.push(applyOperator(infixExpr.charAt(i) + "", value1, value2) + "");
}
}
}
return Integer.parseInt(s.pop());
}
public static int eval(String infix){
return evalPostfix(toPostfix(infix));
}
public static void main(String[] args) {
System.out.println(rank("/"));
String infix = "(a * b) * c + d ^ e / f";
String stat = "5 * 3";
System.out.println(toPostfix(infix));
System.out.print("Using applyOperator method, 7 * 3 = ");
System.out.println(applyOperator("*", 3, 7));
System.out.print("Using applyOperator method, 50 + 12 = ");
System.out.println(applyOperator("+", 50, 12));
System.out.print("Using Math.pow to perform exponentiation, 6 to the 2nd power is: ");
System.out.println(applyOperator("^", 6,2));
System.out.println(eval(stat));
}
}
Related
I wrote a couple of functions that take a formatted string, defines the number of dice and the size of the dice, throw them, and adds their values.
Eg: 3d8 would mean to throw 3 dices of 8 sides each and add their values. The values are always positive, so every time I run this function for 3d8 I could get values between 3 and 24.
public int calcDice(String diceFormula){
String[] divided = diceFormula.split("d");
int cant = Integer.parseInt(divided[0]);
int dice = Integer.parseInt(divided[1]);
int result = 0;
for (int i = 0; i < cant; i++) {
result += throwDice(dice);
}
return result;
}
private int throwDice(int diceSize) {
diceSize = diceSize < 0 ? dice * -1 : diceSize;
Random r = new Random();
return r.nextInt((diceSize - 1) + 1) + 1;
}
What I require now, is to be able to make mathematical functions using these values, so I could input a mathematical function that will be calculated. I would need to respect the resolution order
Eg. ((3d8)+1) x (2d4) x 3
One of the ideas was to take the string and process first the values, then replace the javascript evaluator to figure out the result, but I'm not sure how can I "pick" the values.
(A regex maybe?)
What I did to solve this was to implement a ShuntingYard function that was able to parse mathematical expressions
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ShuttingYard {
private final Map<String, Integer> operators = new HashMap<>();
public ShuttingYard(){
operators.put("-", 0);
operators.put("+", 0);
operators.put("/", 1);
operators.put("*", 1);
operators.put("^", 2);
}
public double doTheShuntingYard(String expression)throws IllegalArgumentException, NumberFormatException, ArithmeticException{
if(expression == null || expression.trim().length() == 0)
throw new IllegalArgumentException("Empty expression or null");
expression = expression.replaceAll("\\s+","");
expression = expression.replace("(-", "(0-");
if (expression.startsWith("-")){
expression = "0" + expression;
}
Pattern pattern = Pattern.compile("((([0-9]*[.])?[0-9]+)|([\\+\\-\\*\\/\\(\\)\\^]))");
Matcher matcher = pattern.matcher(expression);
int counter = 0;
List<String> tokens = new ArrayList<>();
while(matcher.find()){
if(matcher.start() != counter){
throw new IllegalArgumentException("Invalid Expression:" + expression + ". Error between " + counter+ " end " + matcher.start());
}
tokens.add(matcher.group().trim());
counter += tokens.get(tokens.size() - 1 ).length();
}
if(counter != expression.length()){
throw new IllegalArgumentException("Invalid end of expression");
}
Stack<String> stack = new Stack<>();
List<String> output = new ArrayList<>();
for(String token : tokens){
if(operators.containsKey(token)){
while(!stack.empty() &&
operators.containsKey(stack.peek())&&
((operators.get(token) <= operators.get(stack.peek()) && !token.equals("^"))||
(operators.get(token) < operators.get(stack.peek()) && token.equals("^")))){
output.add(stack.pop());
}
stack.push(token);
}
else if(token.equals("(")){
stack.push(token);
}
else if(token.equals(")")){
while(!stack.empty()){
if(!stack.peek().equals("(")){
output.add(stack.pop());
}
else{
break;
}
}
if(!stack.empty()){
stack.pop();
}
}
else{
output.add(token);
}
}
while(!stack.empty()){
output.add(stack.pop());
}
Stack<Double> doubles = new Stack<>();
for(String token : output){
if(!operators.containsKey(token) && token.matches("([0-9]*[.])?[0-9]+")){
try{
doubles.push(Double.parseDouble(token));
}
catch(NumberFormatException n){
throw n;
}
}
else{
if(doubles.size() > 1){
double op1 = doubles.pop();
double op2 = doubles.pop();
switch (token) {
case "+":
doubles.push(op2 + op1);
break;
case "-":
doubles.push(op2 - op1);
break;
case "*":
doubles.push(op2 * op1);
break;
case "/":
if(op1 == 0){
throw new ArithmeticException("Division by 0");
}
doubles.push(Math.floor(op2 / op1));
break;
case "^":
doubles.push(Math.pow(op2, op1));
break;
default:
throw new IllegalArgumentException(token + " is not an operator or is not handled");
}
}
}
}
if(doubles.empty() || doubles.size() > 1){
throw new IllegalArgumentException("Invalid expression, could not find a result. An operator seems to be absent");
}
return doubles.peek();
}
}
Then, I would call this function after resolving the throwDice operations
public class DiceThrower{
private ShuttingYard shuttingYard;
public DiceThrower(){
this.shuttingYard = new ShuttingYard();
}
public void throwDiceAction(View view){
TextView result = findViewById(R.id.diceResult);
try{
String original = ((EditText)findViewById(R.id.formula)).getText().toString();
Pattern pattern = Pattern.compile("([0-9]{1,999})d([0-9]{1,999})");
Matcher matcher = pattern.matcher(original);
while(matcher.find()){
original = matcher.replaceFirst(Integer.toString(calcDice(matcher.group(0))));
matcher = pattern.matcher(original);
}
result.setText(evaluateExpression(original).split("\\.")[0]);
}catch(ArithmeticException e){
result.setText("This doesn't seem to be a valid mathematical expression");
}
}
public String evaluateExpression(String expression){
expression = expression.replaceAll("\\)\\(", ")*(");
expression = expression.replaceAll("x", "*");
return Double.toString(this.shuttingYard.doTheShuntingYard(expression));
}
public int calcDice(String formula){
String[] divided = formula.split("d");
int cant = Integer.parseInt(divided[0]);
int dice = Integer.parseInt(divided[1]);
int result = 0;
for (int i = 0; i < cant; i++) {
result += throwDice(dice);
}
return result;
}
private int throwDice(int dice) {
dice = dice < 0 ? dice * -1 : dice;
Random r = new Random();
return r.nextInt((dice - 1) + 1) + 1;
}
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
Usually, a regular expression can only indicate whether the statement and the rule match. I want to be able to indicate the wrong character when I'm not, what should I do。
Pattern compile = Pattern.compile("[a-zA-Z]*");
Matcher matcher = compile.matcher("abc1ac");
I want to make an error in the character 1.
I want to check a filter,like (name eq '1' or nickname ne '2') and code like '''' and user.name like 'jo%', the value using double '' translation
I write as follow,maybe better to use design pattern.
public class FilterExpressionException extends RuntimeException {
private String expression;
private int index;
public FilterExpressionException(String expression, int index) {
super(mark(expression, index));
this.expression = expression;
this.index = index;
}
public FilterExpressionException(String message, String expression, int index) {
super(message + "(" + mark(expression, index) + ")");
this.expression = expression;
this.index = index;
}
private static String mark(String expression, int index) {
return expression.substring(0, index) + '^' + expression.substring(index);
}
public String getExpression() {
return expression;
}
public int getIndex() {
return index;
}
}
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
public class FilterExpressionParserImpl {
private String[] relations = {"eq", "ne", "gt", "ge", "lt", "le", "like", "in", "bt"};
private String[] logices = {"and", "or"};
private char[][] relationChars = toCharArray(relations);
private char[][] logicChars = toCharArray(logices);
public static void main(String[] args) {
FilterExpressionParserImpl impl = new FilterExpressionParserImpl();
String expr = "(name eq '' or nickname ne '2' ) and (code like '''' or (user.A.name eq '''go''go''go'))";
List<String> parse = impl.parse(expr);
System.out.println(parse);
List<String> strings = impl.followUp(parse);
System.out.println(strings);
}
private class Variable {
Stack<String> words = new Stack<>();
Stack<Character> characters = new Stack<>();
Stack<Integer> brackets = new Stack<>();
int step = 0;
char character;
int commaTimes = 0;
char[][] relations;
char[][] logices;
public Variable(char[][] relations, char[][] logices) {
this.relations = relations;
this.logices = logices;
}
}
private List<String> followUp(List<String> middles) {
List<String> afters = new ArrayList<>(middles.size());
Stack<String> operators = new Stack<>();
String top;
for (String middle : middles) {
switch (middle) {
case "and":
case "or":
if (operators.size() > 0 && !operators.peek().equals("(")) afters.add(operators.pop());
operators.push(middle);
break;
case "(":
operators.push(middle);
break;
case ")":
while (!(top = operators.pop()).equals("(")) afters.add(top);
break;
default:
afters.add(middle);
}
}
while (!operators.isEmpty()) afters.add(operators.pop());
return afters;
}
private List<String> parse(String filter) {
filter = filter.trim();
Variable variable = new Variable(relationChars, logicChars);
for (int i = 0; i < filter.length(); i++) {
variable.character = filter.charAt(i);
switch (variable.character) {
case ' ':
if (variable.characters.isEmpty()) continue;
switch (variable.step) {
case 0:
dealPropertyPathEnd(filter, i, variable);
break;
case 1:
dealRelationEnd(variable);
break;
case 2:
dealValueEnd(filter, i, variable);
break;
case 3:
dealLogicEnd(variable);
break;
}
pushWord(variable);
break;
case '(':
if (variable.step != 0) throw new FilterExpressionException(filter, i);
variable.words.push(String.valueOf(variable.character));
variable.brackets.push(i);
break;
case ')':
if (variable.brackets.size() == 0) throw new FilterExpressionException(filter, i);
variable.brackets.pop();
if (variable.step == 2 && !variable.characters.isEmpty()) {
dealValueEnd(filter, i, variable);
pushWord(variable);
}
if (variable.step != 3) throw new FilterExpressionException(filter, i);
variable.words.push(String.valueOf(variable.character));
break;
default:
switch (variable.step) {
case 0:
if (!(isLetter(variable.character) || variable.character == '.')
|| ((variable.characters.size() == 0 || variable.characters.peek() == '.') && variable.character == '.'))
throw new FilterExpressionException(filter, i);
break;
case 1:
variable.relations = find(variable.relations, variable.characters.size(), variable.character);
if (variable.relations == null) throw new FilterExpressionException(filter, i);
break;
case 2:
if (variable.characters.size() == 0) {
if (variable.character != '\'') throw new FilterExpressionException(filter, i);
}
else {
if (variable.character == '\'') variable.commaTimes++;
else if (variable.commaTimes % 2 != 0) throw new FilterExpressionException(filter, i);
}
break;
case 3:
variable.logices = find(variable.logices, variable.characters.size(), variable.character);
if (variable.logices == null) throw new FilterExpressionException(filter, i);
break;
}
variable.characters.push(variable.character);
break;
}
}
if (!variable.characters.isEmpty()) {
if (variable.characters.peek() != '\'') throw new FilterExpressionException(filter, filter.length() - 1);
if (variable.commaTimes % 2 != 1) throw new FilterExpressionException(filter, filter.length() - 1 - variable.commaTimes);
pushWord(variable);
}
if (!variable.brackets.isEmpty()) throw new FilterExpressionException(filter, variable.brackets.firstElement());
return variable.words;
}
private void pushWord(Variable variable) {
String string = join(variable.characters);
if (variable.step == 3) {
if (string.equals("\'\'")) {
string = "";
} else {
string = string.replace("\'\'", "\'");
string = string.substring(1, string.length() - 1);
}
}
variable.words.push(string);
variable.characters.clear();
}
private String join(List<Character> characters) {
StringBuilder builder = new StringBuilder();
characters.forEach(builder::append);
return builder.toString();
}
private void dealPropertyPathEnd(String filter, int i, Variable variable) {
if (variable.characters.peek() == '.') throw new FilterExpressionException(filter, i);
variable.step = 1;
}
private void dealRelationEnd(Variable variable) {
variable.relations = relationChars;
variable.step = 2;
}
private void dealValueEnd(String filter, int i, Variable variable) {
if (variable.characters.peek() != '\'') throw new FilterExpressionException(filter, i);
if (variable.commaTimes % 2 != 1) throw new FilterExpressionException(filter, i);
variable.commaTimes = 0;
variable.step = 3;
}
private void dealLogicEnd(Variable variable) {
variable.logices = logicChars;
variable.step = 0;
}
private boolean isLetter(char character) {
return ('a' <= character && character <= 'z') || ('A' <= character && character <= 'Z');
}
private char[][] toCharArray(String[] strings) {
char[][] chars = new char[strings.length][];
for (int i = 0; i < strings.length; i++) {
chars[i] = strings[i].toCharArray();
}
return chars;
}
private char[][] find(char[][] sources, int column, char character) {
if (sources == null || sources.length == 0) return sources;
List<Integer> indexes = new ArrayList<>(sources.length);
for (int i = 0; i < sources.length; i++) {
if (sources[i].length > column && sources[i][column] == character) indexes.add(i);
}
if (indexes.isEmpty()) return null;
char[][] targets = new char[indexes.size()][];
for (int i = 0; i < indexes.size(); i++) {
targets[i] = sources[indexes.get(i)];
}
return targets;
}
}
Java's regular expression engine can do much more than just matching text. For more information, read the documentation.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class LookingAt {
public static String validate(String input, Pattern regex) {
Matcher m = regex.matcher(input);
if (m.matches())
return "OK";
if (m.lookingAt())
return "First error at index " + m.end();
if (m.hitEnd())
return "Too short";
return "Cannot match at all";
}
public static void main(String[] args) {
System.out.println(validate("abcac", Pattern.compile("[a-zA-Z]*")));
System.out.println(validate("abc1ac", Pattern.compile("[a-zA-Z]*")));
System.out.println(validate("abcac", Pattern.compile("[a-zA-Z]{10,}")));
System.out.println(validate("1abcac", Pattern.compile("[a-zA-Z]+")));
}
}
I'm trying to create a method that would create an equation for me, as a String.
For example, this method would create:
String formula = "5 + 3";
then another method will solve it.
I don't really know how to create the string. Should i use concat?
Thanks for all the help.
public static String getEquation() {
for(int i=0;i<7;i++){
int rand = rng.nextInt(5);
switch (rand) {
case 0:
operator = "+";
break;
case 1:
operator = "-";
break;
case 2:
operator = "*";
break;
case 3:
operator = "/";
break;
case 4:
operator = "(";
break;
case 5:
operator = ")";
}
}
return formula;
}
Wrote something up really quick, I think this should get you going. You'd have to handle the cases for parentheses though. I didn't account for that.
import java.util.Random;
public class Test {
static Random randomGenerator = new Random();
static String operators = "+-*/P"; //p = parentheses pair
public static char getRandomOperator() {
return operators.charAt(randomGenerator.nextInt(operators.length()));
}
public static int getRandomNumber() {
return randomGenerator.nextInt(100);
}
public static String createEquation() {
//Just for proof of concept, let's do 3 operators
String equation = "";
int numOfOperators = 3;
char operator = ' ';
for (int i = 0; i < numOfOperators; i++) {
equation += getRandomNumber();
equation += getRandomOperator();
}
equation += getRandomNumber();
return equation;
}
public static void main(String[] args) {
String equation = createEquation();
System.out.println(equation);
}
}
I may have time later and come back and address the parentheses issue. For now I just print 'P' where parentheses should be handled.
EDIT
Updated it to handle parentheses. I'm going to paste it down here in case you want to keep it as the old way. Also did a couple tweaks here and there. Note that I didn't handle it matching an exact number of operators when it comes to parenthesis. Which means that if all the open parenthesis weren't closed by the time the loop is done grabbing operators then I append extra parenthesis at the end. Which can result in more than 7 operators. You should probably add logic to either treat a pair of parenthesis as 1 operator or 1 parenthesis as a single operator. Enjoy.
import java.util.Random;
public class Test {
static Random randomGenerator = new Random();
static String operators = "+-*/()";
static int opeatorStringLength = operators.length();
public static char getRandomOperator() {
return operators.charAt(randomGenerator.nextInt(opeatorStringLength));
}
public static int getRandomNumber() {
return randomGenerator.nextInt(100);
}
public static String appendToEquation(String equation, String value1, String value2) {
String temp = equation;
temp += value1;
temp += value2;
return temp;
}
public static String createEquation(int numOfOperators) {
String equation = "";
char operator;
int operand;
int openParenCounter = 0;
for (int i = 0; i < numOfOperators; i++) {
operator = getRandomOperator();
operand = getRandomNumber();
if (operator == '(') {
openParenCounter++;
equation = appendToEquation(equation, Character.toString(operator), Integer.toString(operand));
} else if (operator == ')') {
if (openParenCounter == 0) { //Can't start off with a close parenthesis
openParenCounter++;
equation = appendToEquation(equation, "(", Integer.toString(operand));
} else {
openParenCounter--;
equation = appendToEquation(equation, Integer.toString(operand), Character.toString(operator));
}
} else {
equation = appendToEquation(equation, Integer.toString(operand), Character.toString(operator));
}
}
equation += getRandomNumber();
while (openParenCounter > 0) {
equation += ")";
openParenCounter--;
}
return equation;
}
public static void main(String[] args) {
String equation;
equation = createEquation(7); //The argument passed is the number of operators to use
System.out.println(equation);
}
}
Help me stackoverflow, you're my only hope. I have been trying to make a simple calculator, and finally I've gotten it to WORK! The problem is that only simply expressions are evaluated. For example: 4*5 would give 20.0. (Awesome!)
Whenever I give it a more complicated expression like 4*(2+3), the program crashes due to an EmptyStackException. I understand the exception, but I am unable to recreate the problem in my mind when I run through the code manually with my brain and a sheet of paper.
Can anyone figure out why it's crashing? Here is the full code. I marked where the code crashes with some bold, all-caps words. (i.e. PROGRAM CRASHES HERE)
/**
* Human
* Project 3: SUPER-DUPER JAVA CALCULATOR
*/
import java.util.*;
import java.util.Stack;
import java.lang.String;
import java.util.ArrayList;
import java.lang.StringBuilder;
import java.util.HashSet;
import java.lang.Exception;
import java.lang.Math;
public class InfixEvaluator {
public static class SyntaxErrorException extends Exception {
/**
* Construct a SyntaxErrorException with the specified message.
*
* #param message The message
*/
SyntaxErrorException(String message) {
super(message);
}
}
/**
* This is the stack of operands:
* i.e. (doubles/parentheses/brackets/curly braces)
*/
private static Stack<Double> operandStack = new Stack<Double>();
/**
* This is the operator stack
* i.e. (+-/*%^)
*/
private static Stack<String> operatorStack = new Stack<String>();
/**
* These are the possible operators
*/
private static final String OPERATORS = "+-/*%^()[]{}";
private static final String BRACES = "()[]{}";
private static final String NONBRACES = "+-/*%^";
private static final int[] PRECEDENCE = {1, 1, 2, 2, 2, -1, -1, -1, -1, -1, -1};
/**
* This is an ArrayList of all the discrete
* things (operators/operands) making up an input.
* This is really just getting rid of the spaces,
* and dividing up the "stuff" into manageable pieces.
*/
static ArrayList<String> input = new ArrayList<String>();
public static ArrayList inputCleaner(String postfix) {
StringBuilder sb = new StringBuilder();
String noSpaces = postfix.replace(" ", "");
try {
for (int i = 0; i < noSpaces.length(); i++) {
char c = noSpaces.charAt(i);
boolean isNum = (c >= '0' && c <= '9');
if (isNum) {
sb.append(c);
if (i == noSpaces.length() - 1) {
input.add(sb.toString());
sb.delete(0, sb.length());
}
} else if (c == '.') {
for (int j = 0; j < sb.length(); j++) {
if (sb.charAt(j) == '.') {
throw new SyntaxErrorException("You can't have two decimals in a number.");
} else if (j == sb.length() - 1) {
sb.append(c);
j = (sb.length() + 1);
}
}
if (sb.length() == 0) {
sb.append(c);
}
if (i == noSpaces.length() - 1) {
throw new SyntaxErrorException("You can't end your equation with a decimal!");
}
} else if (OPERATORS.indexOf(c) != -1) {
if (sb.length() != 0) {
input.add(sb.toString());
sb.delete(0, sb.length());
}
sb.append(c);
input.add(sb.toString());
sb.delete(0, sb.length());
} else {
throw new SyntaxErrorException("Make sure your input only contains numbers, operators, or parantheses/brackets/braces.");
}
}
int numLP = 0;
int numRP = 0;
int numLB = 0;
int numRB = 0;
int numLBr = 0;
int numRBr = 0;
for (int f = 0; f < input.size(); f++) {
String trololol = input.get(f);
switch (trololol) {
case "(":
numLP++;
break;
case "[":
numLB++;
break;
case "{":
numLBr++;
break;
case ")":
numRP++;
break;
case "]":
numRB++;
break;
case "}":
numRBr++;
break;
default: //do nothing
break;
}
}
if (numLP != numRP || numLB != numRB || numLBr != numRBr) {
throw new SyntaxErrorException("The number of brackets, braces, or parentheses don't match up!");
}
int doop = 0;
int scoop = 0;
int foop = 0;
for (int f = 0; f < input.size(); f++) {
String awesome = input.get(f);
switch (awesome) {
case "(":
doop++;
break;
case "[":
scoop++;
break;
case "{":
foop++;
break;
case ")":
doop--;
break;
case "]":
scoop--;
break;
case "}":
foop--;
break;
default: //do nothing
break;
}
if (doop < 0 || scoop < 0 || foop < 0) {
throw new SyntaxErrorException("The order of your parentheses, brackets, or braces is off.\nMake sure you open a set of parenthesis/brackets/braces before you close them.");
}
}
if (NONBRACES.indexOf(input.get(input.size() - 1)) != -1) {
throw new SyntaxErrorException("The input can't end in an operator");
}
return input;
} catch (SyntaxErrorException ex) {
System.out.println(ex);
return input;
}
}
/**
* Method to process operators
*
* #param op The operator
* #throws EmptyStackException
*/
private static void processOperator(String op) {
if (operatorStack.empty() || op == "(" || op == "[" || op == "{") {
operatorStack.push(op);
} else {
//peek the operator stack and
//let topOp be the top operator.
String topOp = operatorStack.peek();
if (precedence(op) > precedence(topOp)) {
operatorStack.push(op);
} else {
//Pop all stacked operators with equal
// or higher precedence than op.
while (!operatorStack.empty() && precedence(op) <= precedence(topOp)) {
double r = operandStack.pop();
double l = operandStack.pop();
String work = operatorStack.pop();
switch (work) {
case "+":
operandStack.push(l + r);
break;
case "-":
operandStack.push(l - r);
break;
case "*":
operandStack.push(l * r);
break;
case "/":
operandStack.push(l / r);
break;
case "%":
operandStack.push(l % r);
break;
case "^":
operandStack.push(Math.pow(l, r));
break;
default: //do nothing, but this should never happen
break;
}
if (topOp == "(" || topOp == "[" || topOp == "{") {
//matching '(' popped - exit loop.
operandStack.push(l);
operandStack.push(r);
break;
}
if (!operatorStack.empty()) {
//reset topOp
topOp = operatorStack.peek();
}
}
//assert: Operator stack is empty or
// current operator precedence > top of stack operator precedence.
if (op != ")" || op != "]" || op != "}") {
operatorStack.push(op);
}
}
}
}
public static String infixCalculator(ArrayList<String> puke) {
int p;
for (p = 0; p < puke.size(); p++) {
if (OPERATORS.indexOf(puke.get(p)) == -1) {
double herp = Double.parseDouble(puke.get(p));
operandStack.push(herp);
} else {
processOperator(puke.get(p));
}
}
if (p == puke.size()) {
while (!operatorStack.empty()) {
double r = operandStack.pop();
double l = operandStack.pop();
String work = operatorStack.pop();
switch (work) {
case "+":
operandStack.push(l + r);
break;
case "-":
operandStack.push(l - r);
break;
case "*":
operandStack.push(l * r);
break;
case "/":
operandStack.push(l / r);
break;
case "%":
operandStack.push(l % r);
break;
case "^":
operandStack.push(Math.pow(l, r));
break;
default:
break;
}
}
}
return String.valueOf(operandStack.pop());
}
private static int precedence(String op) {
return PRECEDENCE[OPERATORS.indexOf(op)];
}
public static void main(String[] args) {
do {
try {
ArrayList test = new ArrayList();
Scanner f = new Scanner(System.in);
System.out.println("Please insert an argument: \n");
String g = f.nextLine();
test = inputCleaner(g);
for (int z = 0; z < test.size(); z++) {
System.out.println(test.get(z));
}
System.out.println(infixCalculator(test));
test.clear();
} catch (EmptyStackException e) {
System.out.println("Make sure you only put in operators and operands.");
}
} while (true);
}
}
Stack trace:
java.util.EmptyStackException at
java.util.Stack.peek(Stack.java:102) at
java.util.Stack.pop(Stack.java:84) at
InfixEvaluator.processOperator(InfixEvaluator.java:177) at
InfixEvaluator.infixCalculator(InfixEvaluator.java:225) at
InfixEvaluator.main(InfixEvaluator.java:276)
Your error comes from poping an element off the stack when the stack is empty. Hence the name EmptyStackException.
I noticed in your loops you say something like while(!operatorStack.empty()) but then inside the while loop you pop 2 or sometimes 3 elements off the stack. If you want to pop more elements off an array than one you should test for that in your while loop.
So if you pop 2 elements off then do while (operatorStack.size() > 2 ). I edited your code changing all your while loops to be correct and it worked fine for these inputs
(2+3)
and
(2+3)+5
Here is what I did:
Moved boilerplate code into new methods
Added method signatures comments
Fixed your operator precedence, pow operator had the wrong precedence.
Changed String comparison in a bunch of places from str1 == str2 to str1.equals(str2). You should look at How do I compare strings in Java? to see why I did that.
Added in System.out.println statements to debug your application. I left them in so you can see the output and check it for yourself. You should look through and see what I did to help you debug in the future.
import java.util.*;
import java.util.Stack;
import java.lang.String;
import java.util.ArrayList;
import java.lang.StringBuilder;
import java.util.HashSet;
import java.lang.Exception;
import java.lang.Math;
public class InfixEvaluator
{
public static class SyntaxErrorException extends Exception {
/** Construct a SyntaxErrorException with the specified message.
#param message The message
*/
SyntaxErrorException(String message) {
super(message);
}
}
/** This is the stack of operands:
i.e. (doubles/parentheses/brackets/curly braces)
*/
private static Stack<Double> operandStack = new Stack<Double>();
/** This is the operator stack
* i.e. (+-/*%^)
*/
private static Stack<String> operatorStack = new Stack<String>();
/** These are the possible operators */
private static final String OPERATORS = "+-/*%^()[]{}";
private static final String BRACES = "()[]{}";
private static final String NONBRACES = "+-/*%^";
// + - / * % ^ ( ) [ ] { }
private static final int[] PRECEDENCE = {1, 1, 2, 2, 3, 3, -1, -1, -1, -1, -1, -1};
/** This is an ArrayList of all the discrete
things (operators/operands) making up an input.
This is really just getting rid of the spaces,
and dividing up the "stuff" into manageable pieces.
*/
static ArrayList<String> input = new ArrayList<String>();
/**
* TODO: write this
* #param postfix
* #return
*/
public static ArrayList inputCleaner(String postfix){
StringBuilder sb = new StringBuilder();
String noSpaces = postfix.replace(" ", "");
try {
for (int i = 0; i < noSpaces.length(); i++) {
char c = noSpaces.charAt(i);
boolean isNum = (c >= '0' && c <= '9');
if (isNum) {
sb.append(c);
if (i == noSpaces.length()-1) {
input.add(sb.toString());
sb.delete(0, sb.length());
}
} else if (c == '.') {
for (int j = 0; j < sb.length(); j++) {
if (sb.charAt(j) == '.') {
throw new SyntaxErrorException("You can't have two decimals in a number.");
} else if (j == sb.length() - 1) {
sb.append(c);
j = (sb.length() + 1);
}
}
if (sb.length() == 0) {
sb.append(c);
}
if (i == noSpaces.length()-1) {
throw new SyntaxErrorException("You can't end your equation with a decimal!");
}
} else if (OPERATORS.indexOf(c)!= -1) {
if (sb.length() != 0) {
input.add(sb.toString());
sb.delete(0, sb.length());
}
sb.append(c);
input.add(sb.toString());
sb.delete(0, sb.length());
} else {
throw new SyntaxErrorException("Make sure your input only contains numbers, operators, or parantheses/brackets/braces.");
}
}
int numLP = 0;
int numRP = 0;
int numLB = 0;
int numRB = 0;
int numLBr = 0;
int numRBr = 0;
for (int f = 0; f < input.size(); f++) {
switch (input.get(f)) {
case "(": numLP++;
break;
case "[": numLB++;
break;
case "{": numLBr++;
break;
case ")": numRP++;
break;
case "]": numRB++;
break;
case "}": numRBr++;
break;
default: //do nothing
break;
}
}
if (numLP != numRP || numLB != numRB || numLBr != numRBr) {
throw new SyntaxErrorException("The number of brackets, braces, or parentheses don't match up!");
}
int doop = 0;
int scoop = 0;
int foop = 0;
for (int f = 0; f < input.size(); f++) {
String awesome = input.get(f);
switch (awesome) {
case "(": doop++;
break;
case "[": scoop++;
break;
case "{": foop++;
break;
case ")": doop--;
break;
case "]": scoop--;
break;
case "}": foop--;
break;
default: //do nothing
break;
}
if (doop < 0 || scoop < 0 || foop < 0) {
throw new SyntaxErrorException("The order of your parentheses, brackets, or braces is off.\nMake sure you open a set of parenthesis/brackets/braces before you close them.");
}
}
if (NONBRACES.indexOf(input.get(input.size()-1)) != -1) {
throw new SyntaxErrorException("The input can't end in an operator");
}
return input;
} catch (SyntaxErrorException ex) {
System.out.println(ex);
return input;
}
}
/**Method to process operators
* #param op The operator
* #throws SyntaxErrorException
* #throws EmptyStackException
*/
private static void processOperator(String op) throws SyntaxErrorException {
if (operatorStack.empty() || op.equals("(") || op.equals("[") || op.equals("{")) {
operatorStack.push(op);
} else {
//peek the operator stack and
//let topOp be the top operator.
String topOp = operatorStack.peek();
if (precedence(op) > precedence(topOp)) {
topOp = op;
operatorStack.push(op);
} else {
System.out.println(operatorStack);
System.out.println(operandStack);
System.out.println("--------------");
//Pop all stacked operators with equal
// or higher precedence than op.
while (operandStack.size() >= 2 && !operatorStack.isEmpty()) {
double r = operandStack.pop();
double l = operandStack.pop();
String work = getNextNonBracerOperator();
System.out.println("L:" + l + " R:" + r + " W:" + work);
doOperandWork(work, l, r);
if(op.equals("(") || op.equals("[") || op.equals("{")) {
//matching '(' popped - exit loop.
operandStack.push(l);
operandStack.push(r);
break;
}
if (!operatorStack.empty()) {
//reset topOp
topOp = operatorStack.peek();
}
}
//assert: Operator stack is empty or
// current operator precedence > top of stack operator precedence.
if(!op.equals(")") || !op.equals("}") || !op.equals("}")) {
operatorStack.push(op);
}
}
}
}
/**
* TODO: write this
* #param expressions
* #return
* #throws SyntaxErrorException
*/
public static String infixCalculator(ArrayList<String> expressions) throws SyntaxErrorException {
for (String expression : expressions) {
if (OPERATORS.indexOf(expression) == -1) {
operandStack.push(Double.parseDouble(expression));
} else {
processOperator(expression);
}
}
while (operandStack.size() >= 2 && !operatorStack.isEmpty()) {
System.out.println("--------------");
System.out.println(operandStack);
System.out.println(operatorStack);
double r = operandStack.pop();
double l = operandStack.pop();
String work = getNextNonBracerOperator();
System.out.println("L:" + l + " R:" + r + " W:" + work);
doOperandWork(work, l, r);
}
if(operandStack.isEmpty())
return null;
return String.valueOf(operandStack.pop());
}
/**
* goes through the stack and pops off all non operatable operations until it gets to one that is in the NONBRACES String
* #return The next operatable string
*/
private static String getNextNonBracerOperator() {
String work = "\0"; // \0 is null,
while(!operatorStack.isEmpty() && NONBRACES.indexOf(work) == -1)
work = operatorStack.pop();
return work;
}
/**
*
* #param work The operator you want to work. This really should be a character but its still a string
* #param l Left side number
* #param r Right side number
* #throws SyntaxErrorException If the operator could not be found
*/
private static void doOperandWork(String work, double l, double r) throws SyntaxErrorException {
switch (work) {
case "+": operandStack.push(l+r);
break;
case "-": operandStack.push(l-r);
break;
case "*": operandStack.push(l*r);
break;
case "/": operandStack.push(l/r);
break;
case "%": operandStack.push(l%r);
break;
case "^": operandStack.push(Math.pow(l, r));
break;
default:
throw new SyntaxErrorException("Invalid operand " + work);
}
}
/**
* #param op The operator
* #return the precedence
*/
private static int precedence(String op) {
return PRECEDENCE[OPERATORS.indexOf(op)];
}
public static void main(String[] args) {
try {
ArrayList test = new ArrayList();
Scanner f = new Scanner(System.in);
//System.out.println("Please insert an argument: ");
//String g = f.nextLine();
//String g = "(1+1)^(3+1)";
String g = "(1+3)*3^2+2*4-1";
test = inputCleaner(g);
for (int z = 0; z < test.size(); z++) {
System.out.println(test.get(z));
}
System.out.println(infixCalculator(test));
test.clear();
} catch (SyntaxErrorException e) {
System.out.println("Make sure you only put in operators and operands.");
e.printStackTrace();
}
}
}
You are trying to compare a String with ==. Instead use String.equals(String)
if(!op.equals(")") || !op.equals("]") || !op.equals("}")) {
operatorStack.push(op);
}
...
if (operatorStack.empty() || op.equals("(") || op.equals("[") || op.equals("{")) {
operatorStack.push(op);
} else {
...
if (topOp.equals("(") || topOp.equals("[") || topOp.equals("(")) {
//matching '(' popped - exit loop.
operandStack.push(l);
operandStack.push(r);
break;
}
If you then trace through you code, you will see that you are trying to use "(" as an operator
You have already pushed ")" back onto the stack before you check. You should move the check up.
if (precedence(op) > precedence(topOp)) {
if(!op.equals(")") || !op.equals("]") || !op.equals("}")) {
operatorStack.push(op);
}
}
Final Code
import java.util.*;
public class InfixEvaluator
{
public static void main(String[] args) {
ArrayList test = new ArrayList();
Scanner f = new Scanner(System.in);
System.out.println("Please insert an argument: \n");
String g = f.nextLine();
test = inputCleaner(g);
for (int z = 0; z < test.size(); z++) {
System.out.println(test.get(z));
}
System.out.println(infixCalculator(test));
}
public static class SyntaxErrorException extends Exception {
/** Construct a SyntaxErrorException with the specified message.
#param message The message
*/
SyntaxErrorException(String message) {
super(message);
}
}
/** This is the stack of operands:
i.e. (doubles/parentheses/brackets/curly braces)
*/
private static Stack<Double> operandStack = new Stack<Double>();
/** This is the operator stack
* i.e. (+-/*%^)
*/
private static Stack<String> operatorStack = new Stack<String>();
/** These are the possible operators */
private static final String OPERATORS = "+-/*%^()[]{}";
private static final String BRACES = "()[]{}";
private static final String NONBRACES = "+-/*%^";
private static final int[] PRECEDENCE = {1, 1, 2, 2, 2, -1, -1, -1, -1, -1, -1};
/** This is an ArrayList of all the discrete
things (operators/operands) making up an input.
This is really just getting rid of the spaces,
and dividing up the "stuff" into manageable pieces.
*/
static ArrayList<String> input = new ArrayList<String>();
public static ArrayList inputCleaner(String postfix){
StringBuilder poop = new StringBuilder();
String doody = postfix.replace(" ", "");
try {
for (int i = 0; i < doody.length(); i++) {
char c = doody.charAt(i);
boolean isNum = (c >= '0' && c <= '9');
if (isNum) {
poop.append(c);
if (i == doody.length()-1) {
input.add(poop.toString());
poop.delete(0, poop.length());
}
} else if (c == '.') {
for (int j = 0; j < poop.length(); j++) {
if (poop.charAt(j) == '.') {
throw new SyntaxErrorException("You can't have two decimals in a number.");
} else if (j == poop.length() - 1) {
poop.append(c);
j = (poop.length() + 1);
}
}
if (poop.length() == 0) {
poop.append(c);
}
if (i == doody.length()-1) {
throw new SyntaxErrorException("You can't end your equation with a decimal!");
}
} else if (OPERATORS.indexOf(c)!= -1) {
if (poop.length() != 0) {
input.add(poop.toString());
poop.delete(0, poop.length());
}
poop.append(c);
input.add(poop.toString());
poop.delete(0, poop.length());
} else {
throw new SyntaxErrorException("Make sure your input only contains numbers, operators, or parantheses/brackets/braces.");
}
}
int numLP = 0;
int numRP = 0;
int numLB = 0;
int numRB = 0;
int numLBr = 0;
int numRBr = 0;
for (int f = 0; f < input.size(); f++) {
String trololol = input.get(f);
switch (trololol) {
case "(": numLP++;
break;
case "[": numLB++;
break;
case "{": numLBr++;
break;
case ")": numRP++;
break;
case "]": numRB++;
break;
case "}": numRBr++;
break;
default: //do nothing
break;
}
}
if (numLP != numRP || numLB != numRB || numLBr != numRBr) {
throw new SyntaxErrorException("The number of brackets, braces, or parentheses don't match up!");
}
int doop = 0;
int scoop = 0;
int foop = 0;
for (int f = 0; f < input.size(); f++) {
String awesome = input.get(f);
switch (awesome) {
case "(": doop++;
break;
case "[": scoop++;
break;
case "{": foop++;
break;
case ")": doop--;
break;
case "]": scoop--;
break;
case "}": foop--;
break;
default: //do nothing
break;
}
if (doop < 0 || scoop < 0 || foop < 0) {
throw new SyntaxErrorException("The order of your parentheses, brackets, or braces is off.\nMake sure you open a set of parenthesis/brackets/braces before you close them.");
}
}
if (NONBRACES.indexOf(input.get(input.size()-1)) != -1) {
throw new SyntaxErrorException("The input can't end in an operator");
}
return input;
} catch (SyntaxErrorException ex) {
System.out.println(ex);
return input;
}
}
/**Method to process operators
* #param op The operator
* #throws EmptyStackException
*/
private static void processOperator(String op) {
if (operatorStack.empty() || op.equals("(") || op.equals("[") || op.equals("{")) {
operatorStack.push(op);
} else {
//peek the operator stack and
//let topOp be the top operator.
String topOp = operatorStack.peek();
if (precedence(op) > precedence(topOp)) {
if(!op.equals(")") || !op.equals("]") || !op.equals("}")) {
operatorStack.push(op);
}
}
else {
//Pop all stacked operators with equal
// or higher precedence than op.
while (!operatorStack.empty() && precedence(op) <= precedence(topOp)) {
double r = operandStack.pop();
double l = operandStack.pop(); //***THE PROGRAM CRASHES HERE***
String work = operatorStack.pop();
switch (work) {
case "+": operandStack.push(l+r);
break;
case "-": operandStack.push(l-r);
break;
case "*": operandStack.push(l*r);
break;
case "/": operandStack.push(l/r);
break;
case "%": operandStack.push(l%r);
break;
case "^": operandStack.push(Math.pow(l, r));
break;
default: //do nothing, but this should never happen
break;
}
if (topOp.equals("(") || topOp.equals("[") || topOp.equals("(")) {
//matching '(' popped - exit loop.
operandStack.push(l);
operandStack.push(r);
break;
}
if (!operatorStack.empty()) {
//reset topOp
topOp = operatorStack.peek();
}
}
//assert: Operator stack is empty or
// current operator precedence > top of stack operator precedence.
}
}
}
public static String infixCalculator(ArrayList<String> puke) {
int p;
for (p = 0; p < puke.size(); p++) {
if (OPERATORS.indexOf(puke.get(p)) == -1) {
double herp = Double.parseDouble(puke.get(p));
operandStack.push(herp);
} else {
processOperator(puke.get(p));
}
}
if (p == puke.size()) {
while (!operatorStack.empty()) {
double r = operandStack.pop();
double l = operandStack.pop();
String work = operatorStack.pop();
switch (work) {
case "+": operandStack.push(l+r);
break;
case "-": operandStack.push(l-r);
break;
case "*": operandStack.push(l*r);
break;
case "/": operandStack.push(l/r);
break;
case "%": operandStack.push(l%r);
break;
case "^": operandStack.push(Math.pow(l, r));
break;
default: //do nothing, but this should never happen
break;
}
}
}
return String.valueOf(operandStack.pop());
}
private static int precedence(String op) {
return PRECEDENCE[OPERATORS.indexOf(op)];
}
}
This question already has answers here:
Handling parenthesis while converting infix expressions to postfix expressions
(2 answers)
Closed 5 years ago.
I have this homework in Java where I have to convert an infix string without parenthesis to a postfix string. I've been tinkering with the code from two days but I haven't been able to catch the bug. Here's my code.
public class itp
{
String exp, post;
double res;
int l;
stack st;
public itp(String s)
{
exp = s;
post = "";
l = exp.length();
st = new stack(l);
conv();
calc();
System.out.println("The postfix notation of "+exp+" is "+post);
System.out.println("The result of "+exp+" is "+res);
}
public void conv()
{
char ch = ' ';
char pre = ' ';
for(int i =0;i<l;i++)
{
ch = exp.charAt(i);
if("+-*/".indexOf(ch)==-1)post = post + ch;
else
{
pre = st.pop();
if(val(ch)>=val(pre))
{
st.push(pre);
st.push(ch);
}
else
{
while((val(ch)<=val(pre))&&(pre!='$'))
{
post = post + pre;
pre = st.pop();
}
st.push(ch);
}
}
}
for(pre = st.pop();pre!='$';pre = st.pop())
{
post = post + pre;
}
}
public void calc()
{
res = 0.0;
}
public int val(char c)
{
switch(c)
{
case '$' : return 0;
case '+' : return 1;
case '-' : return 2;
case '*' : return 3;
case '/' : return 4;
default : return -1;
}
}
}
Here, the variables are as follows:
st is a character stack
ch is the current character
pre is the topmost char on the stack
exp is the input infix expression
post is the output postfix expression
The pop() methods works as expected except when the stack is empty, where it will return $. The function val() takes a char input and returns 4 for /, 3 for *. 2 for -. 1 for +. The integer l holds the length of exp.
It works well in most cases except when I give it a string like a*b-b*c+c*d-d*e where it outputs ab*bc*-cd*de*- which is the expected output without a + in the end.
Any advice would be much appreciated. This bug is making me crazy!
Here's the entire code:
public class itp
{
String exp, post;
double res;
int l;
stack st;
public itp(String s)
{
exp = s;
post = "";
l = exp.length();
st = new stack(l);
conv();
calc();
System.out.println("The postfix notation of "+exp+" is "+post);
System.out.println("The result of "+exp+" is "+res);
}
public void conv()
{
char ch = ' ';
char pre = ' ';
for(int i =0;i<l;i++)
{
ch = exp.charAt(i);
if("+-*/".indexOf(ch)==-1)post = post + ch;
else
{
pre = st.pop();
if(val(ch)>=val(pre))
{
st.push(pre);
st.push(ch);
}
else
{
while((val(ch)<=val(pre))&&(pre!='$'))
{
post = post + pre;
pre = st.pop();
}
st.push(ch);
}
}
}
for(pre = st.pop();pre!='$';pre = st.pop())
{
post = post + pre;
}
}
public void calc()
{
res = 0.0;
}
public int val(char c)
{
switch(c)
{
case '$' : return 0;
case '+' : return 1;
case '-' : return 2;
case '*' : return 3;
case '/' : return 4;
default : return -1;
}
}
}
here's the stack class:
public class stack
{
char[] a;
int top,size;
public stack(int s)
{
size = s;
a = new char[size];
top = -1;
}
public void push(char el)
{
a[++top] = el;
}
public char pop()
{
if(empty()) return '$';
else return a[top--];
}
public boolean empty()
{
return (top == -1);
}
}
Here's the main class
import java.util.Scanner;
class client
{
public static void main(String args[])
{
System.out.println("Enter the expression");
Scanner in = new Scanner(System.in);
itp i = new itp(in.next());
}
}
First of all the post fix of a*b-b*c+c*d-d*e is not ab*bc*-cd*de*-+ but ab*bc*-cd*+de*-.
Secondly the mistake is in your val() function. It should instead be :
case '$' : return 0;
case '+' : return 1;
case '-' : return 1;
case '*' : return 2;
case '/' : return 2;
default : return -1;
Change it and check. It will certainly work.