patternjavaMinor
Infix to Postfix Formula Parser Java
Viewed 0 times
parserpostfixinfixjavaformula
Problem
I've written a program that takes a mathematical formula as an user input and converts it from infix to postfix.
It doesn't support negative numbers.
The program doesn't depend on the user having to pay attention on how to use spaces, so '1+23' and '1 + 2 3' are the same. (formulas like 'x^2^3' however must be written like 'x^(2^3)')
It provides support for the following operators: +, -, *, /, ^
Originally I had written a stack class completely myself, but this one (credits for stack class go to users of that post) is much more useful/reusable so I updated mine.
Here is the
```
import java.util.Scanner;
public class InfixToPostfix {
//checks whether c is operator
private static boolean isOperator(char c) {
if (c == '+' || c == '-' || c == '*' || c == '/' ||
c == '^' || c == '(' || c == ')') {
return true;
It doesn't support negative numbers.
The program doesn't depend on the user having to pay attention on how to use spaces, so '1+23' and '1 + 2 3' are the same. (formulas like 'x^2^3' however must be written like 'x^(2^3)')
It provides support for the following operators: +, -, *, /, ^
Originally I had written a stack class completely myself, but this one (credits for stack class go to users of that post) is much more useful/reusable so I updated mine.
import java.util.EmptyStackException;
public class MyStack {
private T[] data;
private int numElements;
public MyStack(int capacity) {
data = newArray(capacity);
numElements = 0;
}
private final T[] newArray(int capacity) {
@SuppressWarnings("unchecked")
T[] tmp = (T[]) new Object[capacity];
return tmp;
}
private void enlarge() {
T[] temp = data;
data = newArray(temp.length * 2);
System.arraycopy(temp, 0, data, 0, temp.length);
}
public void push(T element) {
if (numElements == data.length) {
enlarge();
}
else {
data[numElements++] = element;
}
}
public T peek() {
if (isEmpty()) {
throw new EmptyStackException();
}
return data[numElements - 1];
}
public boolean isEmpty() {
return (numElements == 0);
}
public T pop() {
if (isEmpty()) {
throw new EmptyStackException();
}
return data[--numElements];
}
}Here is the
InfixToPostfixclass itself:```
import java.util.Scanner;
public class InfixToPostfix {
//checks whether c is operator
private static boolean isOperator(char c) {
if (c == '+' || c == '-' || c == '*' || c == '/' ||
c == '^' || c == '(' || c == ')') {
return true;
Solution
Standard Stack
Try to use the standard implementation of a stack like java.util.ArrayDeque. You have reinvented the wheel here.
State Pattern
Introduce the state pattern. I here provide you an example.
This parser searches for numbers and returns them. Whitespaces separate numbers as whitespaces are allowed to occur multiple times. If you input alphanumeric characters the machine goes into the Error-State.
The main point is to avoid nested if-statements and have clear responsibilities during parsing. Furthermore your solution lacks extendability. If new requirements occur the state pattern helps you to manage them in a well-defined way.
Fir
Try to use the standard implementation of a stack like java.util.ArrayDeque. You have reinvented the wheel here.
State Pattern
Introduce the state pattern. I here provide you an example.
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
public class NumberParser {
public static void main(String[] args) {
List parse = new NumberParser(" 10 22 32 ").parse();
for (BigInteger bigInteger : parse) {
System.out.println(bigInteger);
}
}
private List numbers;
private final StringBuffer stringToParse;
private final StringBuffer buffer;
private State state;
public NumberParser(String string) {
this.stringToParse = new StringBuffer(string);
this.buffer = new StringBuffer();
this.setState(new Unknown());
}
private boolean hasCurrentChar() {
return this.stringToParse.length() > 0;
}
private char removeCurrentChar() {
if (hasCurrentChar()) {
char ch = this.stringToParse.charAt(0);
this.stringToParse.deleteCharAt(0);
return ch;
} else {
throw new NoSuchElementException();
}
}
private char currentChar() {
if (this.stringToParse.length() > 0) {
return this.stringToParse.charAt(0);
} else {
throw new NoSuchElementException();
}
}
private void clearBuffer() {
buffer.setLength(0);
}
private void recognizeNumber() {
numbers.add(new BigInteger(buffer.toString()));
clearBuffer();
}
public List parse() {
if (numbers == null) {
this.numbers = new ArrayList<>();
while (!(getState() instanceof End)) {
getState().parse();
}
}
return this.numbers;
}
private State getState() {
return state;
}
private void setState(State state) {
System.out.println(state.getStateInfo());
this.state = state;
}
private interface State {
public String getStateInfo();
public void parse();
}
private interface End extends State {
}
private class Error implements End {
@Override
public String getStateInfo() {
return "Something went wrong ...";
}
@Override
public void parse() {
}
}
private class NoMoreChars implements End {
@Override
public String getStateInfo() {
return "No chars left.";
}
@Override
public void parse() {
}
}
private class RemoveWhiteSpaces implements State {
@Override
public String getStateInfo() {
return "Removing white spaces.";
}
@Override
public void parse() {
if (hasCurrentChar()) {
if (Character.isWhitespace(currentChar())) {
removeCurrentChar();
} else {
setState(new Unknown());
}
} else {
setState(new NoMoreChars());
}
}
}
private class Number implements State {
@Override
public String getStateInfo() {
return "Parse digits.";
}
@Override
public void parse() {
if (hasCurrentChar()) {
if (Character.isDigit(currentChar())) {
buffer.append(currentChar());
removeCurrentChar();
} else {
recognizeNumber();
setState(new Unknown());
}
} else {
recognizeNumber();
setState(new NoMoreChars());
}
}
}
private class Unknown implements State {
@Override
public String getStateInfo() {
return "Search ...";
}
@Override
public void parse() {
if (hasCurrentChar()) {
if (Character.isWhitespace(currentChar())) {
setState(new RemoveWhiteSpaces());
} else if (Character.isDigit(currentChar())){
setState(new Number());
} else {
setState(new Error());
}
} else {
setState(new NoMoreChars());
}
}
}
}This parser searches for numbers and returns them. Whitespaces separate numbers as whitespaces are allowed to occur multiple times. If you input alphanumeric characters the machine goes into the Error-State.
The main point is to avoid nested if-statements and have clear responsibilities during parsing. Furthermore your solution lacks extendability. If new requirements occur the state pattern helps you to manage them in a well-defined way.
Fir
Code Snippets
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
public class NumberParser {
public static void main(String[] args) {
List<BigInteger> parse = new NumberParser(" 10 22 32 ").parse();
for (BigInteger bigInteger : parse) {
System.out.println(bigInteger);
}
}
private List<BigInteger> numbers;
private final StringBuffer stringToParse;
private final StringBuffer buffer;
private State state;
public NumberParser(String string) {
this.stringToParse = new StringBuffer(string);
this.buffer = new StringBuffer();
this.setState(new Unknown());
}
private boolean hasCurrentChar() {
return this.stringToParse.length() > 0;
}
private char removeCurrentChar() {
if (hasCurrentChar()) {
char ch = this.stringToParse.charAt(0);
this.stringToParse.deleteCharAt(0);
return ch;
} else {
throw new NoSuchElementException();
}
}
private char currentChar() {
if (this.stringToParse.length() > 0) {
return this.stringToParse.charAt(0);
} else {
throw new NoSuchElementException();
}
}
private void clearBuffer() {
buffer.setLength(0);
}
private void recognizeNumber() {
numbers.add(new BigInteger(buffer.toString()));
clearBuffer();
}
public List<BigInteger> parse() {
if (numbers == null) {
this.numbers = new ArrayList<>();
while (!(getState() instanceof End)) {
getState().parse();
}
}
return this.numbers;
}
private State getState() {
return state;
}
private void setState(State state) {
System.out.println(state.getStateInfo());
this.state = state;
}
private interface State {
public String getStateInfo();
public void parse();
}
private interface End extends State {
}
private class Error implements End {
@Override
public String getStateInfo() {
return "Something went wrong ...";
}
@Override
public void parse() {
}
}
private class NoMoreChars implements End {
@Override
public String getStateInfo() {
return "No chars left.";
}
@Override
public void parse() {
}
}
private class RemoveWhiteSpaces implements State {
@Override
public String getStateInfo() {
return "Removing white spaces.";
}
@Override
public void parse() {
if (hasCurrentChar()) {
if (Character.isWhitespace(currentChar())) {
removeCurrentChar();
} else {
setState(new Unknown());
Context
StackExchange Code Review Q#112091, answer score: 2
Revisions (0)
No revisions yet.