Converting from Infix to PostFix Parentheses Issue - java

Currently, I am working on a method to convert from Infix notation to Postfix notation. I've been writing multiple JUnit tests and regular things like 2*2 or 1+3 are working but anything with parentheses is not working.
For example, (5+2) * (3*5)
During debugging, I always see that my postFixResult string always has the first parentheses added on to the so the beginning of the string is 5 ( 2. I'm not sure what I am doing wrong as I have followed multiple posts around here regarding this problem.
public static String infixToPostFix(String message) throws PostFixException {
MyStack<Character> operatorStack = new MyStack<Character>();
String postFixResult = "";
Scanner tokenizer = new Scanner(message);
while (tokenizer.hasNext()) {
if (tokenizer.hasNextInt()) {
postFixResult += " " + tokenizer.nextInt();
} else {
String value = tokenizer.next();
Operator op = new Operator(value.charAt(0));
char c = value.charAt(0);
String operators = "*/-+()";
if (!isOperator(c)) {
//If the character is not an operator or a left parentheses.
throw new PostFixException("Invalid Operator");
} else {
if (c == ')') {
while (!operatorStack.isEmpty() && operatorStack.peek() != '(') {
postFixResult += " " + operatorStack.pop();
}
if (!operatorStack.isEmpty()) {
operatorStack.pop();
}
}
else {
if (!operatorStack.isEmpty() && !isLowerPrecedence(c, operatorStack.peek())) {
operatorStack.push(c);
}
else {
while (!operatorStack.isEmpty() && isLowerPrecedence(c, operatorStack.peek())) {
Character pop = operatorStack.pop();
if (c != '(') {
postFixResult += " " + pop;
} else {
c = pop;
}
}
operatorStack.push(c);
}
}
}
}
}
while (!operatorStack.isEmpty()) {
postFixResult += " " + operatorStack.pop();
}
return postFixResult;
}
/**
* Method that returns true if c is an operator.
* #param c
* #return
*/
private static boolean isOperator(char c)
{
return c == '+' || c == '-' || c == '*' || c == '/' || c == '^'
|| c == '(' || c == ')';
}
/**
* Determines whether or not the character is actually a number.
* #param c
* #return true if character is number false, otherwise.
*/
private boolean isNumber(char c){
return Character.isDigit(c);
}
/**
* A method to determine precedence of operators.
* #param c1 Operator 1
* #param c2 Operator 2
* #return true if c2 is lower precedence than c1.
*/
private static boolean isLowerPrecedence(char c1, char c2)
{
switch (c1)
{
case '+':
case '-':
return !(c2 == '+' || c2 == '-');
case '*':
case '/':
return c2 == '^' || c2 == '(';
case '^':
return c2 == '(';
case '(':
return true;
default:
//means that the character must have passed through as something else.
return false;
}
}

Parentheses are not needed in a postfix expression, that's the beauty of it. '(' and ')' should not go into your end result(postfix) and should be discarded when popped from the stack itself.

Related

Wont produce the expected output Truthtable in java using stack

This is my code:
import java.util.*;
public class TruthTable {
public static boolean evaluateExpression(String expression, boolean p, boolean q) {
Stack<Boolean> stack = new Stack<>();
Stack<Character> opStack = new Stack<>();
for (int i = 0; i < expression.length(); i++) {
char c = expression.charAt(i);
if (c == 'p') {
stack.push(p);
} else if (c == 'q') {
stack.push(q);
} else if (c == '¬') {
boolean b = stack.pop();
stack.push(!b);
} else if (c == '∧') {
// Check if the next character is a ¬ character.
if (i + 1 < expression.length() && expression.charAt(i + 1) == '¬') {
// If the next character is a ¬ character, pop the top of the stack and negate it,
// then push the conjunction of the negated value and the value of q.
boolean b = stack.pop();
stack.push(!(b && q));
// Increment the index to skip the ¬ character.
i++;
} else {
// If the next character is not a ¬ character, simply push the conjunction of the
// value of p and the value of q.
stack.push(stack.pop() && q);
}
} else if (c == '∨' || c == '→' || c == '↔' || c == '⊕' || c == '⊼' || c == '⊽') {
while (!opStack.isEmpty() && getPrecedence(c) <= getPrecedence(opStack.peek())) {
char op = opStack.pop();
applyOperator(op, stack);
}
opStack.push(c);
}
}
while (!opStack.isEmpty()) {
char op = opStack.pop();
applyOperator(op, stack);
}
return stack.pop();
}
private static void applyOperator(char op, Stack<Boolean> stack) {
boolean b1 = stack.pop();
boolean b2 = stack.pop();
switch (op) {
case '∧':
stack.push(b1 && b2);
break;
case '∨':
stack.push(b1 || b2);
break;
case '→':
stack.push(!b1 || b2);
break;
case '↔':
stack.push(b1 == b2);
break;
case '⊕':
stack.push(b1 != b2);
break;
case '⊼':
stack.push((b1 && b2) || (!b1 && b2) || (b1 && !b2));
break;
case '⊽':
stack.push(b1 && b2 && stack.pop());
break;
case '¬':
stack.push(!b1);
break;
}
}
private static int getPrecedence(char op) {
switch (op) {
case '¬':
return 3;
case '∧':
return 2;
case '∨':
return 1;
case '→':
return 0;
case '↔':
return 0;
case '⊕':
return 1;
case '⊼':
if (op == '∨' || op == '→' || op == '↔' || op == '⊕') {
return 2;
} else {
return 3;
}
case '⊽':
return 2;
default:
return -1;
}
}
public static void main(String[] args) {
String expression = "pq¬∨pq∧→";
System.out.println("p\tq\t(" + expression + ")");
for (boolean p : new boolean[]{true, false}) {
for (boolean q : new boolean[]{true, false}) {
System.out.println(p + "\t" + q + "\t" + evaluateExpression(expression, p, q));
}
}
}
}
The expected result is true false true false but it prints out false true false true and ive been trying to figure out how to fix it but I just cant. Will appreciate any help
Ive tried changing the precedence but it only produced the output True true true true
I don't expect many people will be able to help you, especially if you cannot see the logic error and you are the author!
When writing code like this, your best option is to write Unit Tests. Test parts of the implementation first and then give your algorithm expressions bit by bit and work up to more complex cases.
Note that your use of private static methods may frustrate your ability to test parts or mock out parts of the code. Go find an article about Unit Testing and Dependency Injection; it will be worthwhile your investment.

How to skip comments in java when reading from a text file [closed]

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 2 years ago.
Improve this question
What I'm trying to do is make it so that when the text file is read the comments within in the text file are ignored and not printed along will everything else.
This is the code I have atm and the first part which skips single line comments works however the second part where it tries to skip block comments just doesn't work and the following error message is given
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 186
at java.base/java.lang.StringLatin1.charAt(StringLatin1.java:48)
at java.base/java.lang.String.charAt(String.java:712)
at Q3.scan(Q3.java:281)
at Q3.main(Q3.java:15)
Any help would be great. I can't really change the style of the way it currently is too much either
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
public class Q3 {
public static void main(String[] args) {
System.out.println("Q3Example1:");
String prog1 = readFile2String("src/Q3Example1.txt");
scan(prog1);
System.out.println("\nQ3Example2:");
String prog2 = readFile2String("src/Q3Example2.txt");
scan(prog2);
//fix block comments
}
/**
* takes the input operator and finds the operator tokentype
* #param ch is the current character
* #return the corresponding tokentype
*/
public static TokenType getOp(char ch) {
TokenType t = null;
if(ch == '+') t = TokenType.OP_ADD;
else if (ch == '-') t = TokenType.OP_SUBTRACT;
else if (ch == '*') t = TokenType.OP_MULTIPLY;
else if (ch == '/') t = TokenType.OP_DIVIDE;
else if (ch == '%') t = TokenType.OP_MOD;
else if (ch == '<') t = TokenType.OP_LESS;
else if (ch == '>') t = TokenType.OP_GREATER;
else if (ch == '=') t = TokenType.OP_ASSIGN;
return t;
}
/**
* takes the input double operator and finds the Double operator tokentype
* #param s is the double operator that is input
* #return the corresponding tokentype to the double operator
*/
public static TokenType getOp(String s) {
TokenType t = null;
if(s.equals("<=")) t = TokenType.OP_LESSEQUAL;
if(s.equals(">=")) t = TokenType.OP_GREATEREQUAL;
if(s.equals("==")) t = TokenType.OP_EQUAL;
if(s.equals("!=")) t = TokenType.OP_NOTEQUAL;
return t;
}
/**
* takes the input character and finds the Symbol tokentype
* #param ch is the current character at the index
* #return the corresponding tokentype if it equals any of the symbol characters
*/
public static TokenType getSymbol(char ch) {
TokenType t = null;
if(ch == '(') t = TokenType.LEFT_PAREN;
else if (ch == ')') t = TokenType.RIGHT_PAREN;
else if (ch == '{') t = TokenType.LEFT_BRACE;
else if (ch == '}') t = TokenType.RIGHT_BRACE;
else if (ch == '[') t = TokenType.LEFT_BRACKET;
else if (ch == ']') t = TokenType.RIGHT_BRACKET;
else if (ch == ';') t = TokenType.SEMICOLON;
else if (ch == ',') t = TokenType.COMMA;
return t;
}
/**
* takes the input string and finds the Keyword tokentype
* #param s the input string
* #return if the string equals any of the else if parameters the keyword tokentype is returned
*/
public static TokenType getKeyword(String s) {
TokenType t = null;
if(s.equals("if")) t = TokenType.KEYWORD_IF;
else if (s.equals("else")) t = TokenType.KEYWORD_ELSE;
else if (s.equals("int")) t = TokenType.KEYWORD_INT;
else if (s.equals("String")) t = TokenType.KEYWORD_STRING;
else if (s.equals("public")) t = TokenType.KEYWORD_PUBLIC;
else if (s.equals("class")) t = TokenType.KEYWORD_CLASS;
else if (s.equals("void")) t = TokenType.KEYWORD_VOID;
else if (s.equals("static")) t = TokenType.KEYWORD_STATIC;
return t;
}
/**
* takes the input string and finds the Klingon tokentype
* #param s the input string
* #return the corresponding tokentype for the string else null
*/
public static TokenType getKlingon(String s) {
TokenType t = null;
if(s.equals("rItlh")) t = TokenType.KLINGON_PRINT;
else if (s.equals("boq")) t = TokenType.KLINGON_ADD;
else if (s.equals("boqha")) t = TokenType.KLINGON_SUBTRACT;
else if (s.equals("boqegh")) t = TokenType.KLINGON_MULTIPLY;
else if (s.equals("boqHaegh")) t = TokenType.KLINGON_DIVIDE;
return t;
}
/**
* checks if the current character is a letter from a-z or A-Z
* #param ch input character
* #return if character is a letter then isLetter returns true else false
*/
public static boolean isLetter(char ch) {
if(ch >='a' && ch<='z') return true;
else if(ch >= 'A' && ch <= 'Z') return true;
else return false;
}
/**
* this is a method for including special symbols within strings and checks if any of the input characters correspond to any of the else if branches
* #param ch input character
* #return either true or false depending on the input character
*/
public static boolean isSpecialSymbol(char ch) {
if(ch == ':')return true;
else if(ch == '#')return true;
else if (ch == ',')return true;
else if (ch == '?')return true;
else if (ch == '#')return true;
else if (ch == '$')return true;
else if (ch == '£')return true;
else if (ch == '!')return true;
else if (ch == '^')return true;
else if (ch == '.')return true;
else if (ch == '~')return true;
else return false;
}
/**
* This method just checks if it is a digit at the current index
* #param ch input character
* #return either true if it is a digit or false if its not
*/
public static boolean isDigit(char ch) {
if(ch >='0' && ch<='9') return true;
else return false;
}
/**
* This checks for white space
* #param ch input character
* #return true if there is whitespace or false if there isn't
*/
public static boolean isWhiteSpace(char ch) {
if (ch == ' ')return true;
else if(ch == '\t')return true;
else return false;
}
/**
* checks for a new line or a line break
* #param ch input character
* #return true if there is a line break or false if there isn't
*/
public static boolean isLineBreak(char ch) {
if(ch == '\n') return true;
else return false;
}
/**
* reads the specified file
* #param fname the required file name
* #return the content of the file
*/
public static String readFile2String (String fname) {
String content = null;
try {
content = new String(Files.readAllBytes(Paths.get(fname)));
} catch (IOException e){
System.out.println("Fail to read a file");
}
return content;
}
/**
* this takes the input string, reads it and assigns keywords, line numbers etc to each string, letter, mathematical sign
* #param prog the input string
*/
public static void scan(String prog) {
int n = prog.length(); // n = to the length of the string being scanned
int index = 0;
int linenumber = 1;
while (index < n) { // while the current character is less than the total characters the loop will run
char ch = prog.charAt(index);
char ch_next = ' ';
char ch_next2 = ' ';
if (index < n-1) ch_next = prog.charAt(index+1);
if (index < n-2) ch_next2 = prog.charAt(index+2);
boolean blockComment;
boolean whiteSpace = isWhiteSpace(ch);
boolean newline = isLineBreak(ch);
TokenType sym = getSymbol(ch);
TokenType op = getOp(ch);
boolean letter = isLetter(ch);
boolean digit = isDigit(ch);
if (whiteSpace) { // if there is whitespace then it skips it and moves to the next character
index++;
continue;
} else if (newline) {// if there is a new line then the line number is increased by one and the index increases by one
linenumber++;
index++;
continue;
} else if(ch == '/' && ch_next == '/'){
index++;
index++;
ch = prog.charAt(index);
while(ch != '\n') {
index++;
ch = prog.charAt(index);
}
continue;
} else if(ch == '/' && ch_next == '*' && ch_next2 == '*'){
blockComment = true;
index++;
index++;
index++;
ch = prog.charAt(index);
while(blockComment) {
index++;
ch = prog.charAt(index);
if(ch == '*' && ch_next == '/') {
blockComment = false;
}
}
continue;
} else if (sym != null) { // getSymbol is called and if it doesn't return null then this is carried out
System.out.println(linenumber + ", " + sym + ", " + ch);
index++; // the index is increased and the loop is continued to the next character
continue;
} else if (op != null || ch == '!') { // if getOp(ch) doesn't return null or the ch == ! then this is carried out
String operator = ""; // string operator is made
operator += ch; // operator == the current character
index++; // index increases by one to check the next character
while (index < n) { // this while loop adds the next character onto the current character in operator
ch = prog.charAt(index);
operator += ch;
if (getOp(operator) != null) { // if the string operator doesn't return null it means its a double operator so this is carried out and the while statement ends
System.out.println(linenumber + ", " + getOp(operator) + ", " + operator);
break;
} else if (getOp(operator) == null) // if the operator does return null when put into getOp(s) then it must be a single operator and so this branch is carried out
index--; // the index is reduced by one to return it to the previous operator (the single operator)
ch = prog.charAt(index); //ch is assigned to the current character so that it equals the single operator
System.out.println(linenumber + ", " + op + ", " + ch);
break;
}
index++; // index and continue to the next character
continue;
} else if (letter) { // if the current character is a letter then this branch is executed
String word = ""; // similar to the last else if branch new string is made for the word
word += ch; // the word is built up
index++;// move onto the next character
while (index < n) { // while the current index is less than the total the loop will continue
ch = prog.charAt(index);
if (isLetter(ch) || isDigit(ch)) { // the loop takes the current letter and adds it onto the word until it hits something that isn't a letter and then stops
word += ch;
index++;
} else
break;
}
// once the word is made the word runs through the two methods getKeyword and getKlingon to find its tokentype
TokenType keyword = getKeyword(word);
TokenType klingon = getKlingon(word);
// this checks which method didn't return null and if neither klingon or keyword returned a value then it is assigned the identifier tokentype
if (keyword!= null) {
System.out.println(linenumber + ", " + keyword + ", " + word);
} else if(klingon != null) {
System.out.println(linenumber + ", " + klingon + ", " + word);
} else {
System.out.println(linenumber + ", " + TokenType.IDENTIFIER + ", " + word);
continue;
}
} else if (digit) {
// the same process as the word builder
String number = "";
number += ch;
index++;
while(index < n) {
ch = prog.charAt(index);
if(isDigit(ch)) {
number += ch;
index++;
} else break;
}
System.out.println(linenumber + ", " + TokenType.INTEGER + ", " + number);
continue;
} else if (ch == '\"') { // once a double quotation mark is encountered this string takes place
String str = "";// new string made
str += ch;// current character is added to the current string
index++;// index increases by one
while(index < n) { // this loop builds the string literal by adding characters as long as the index is less than the total string length
ch = prog.charAt(index);
if(isLetter(ch)) { // all of these branches check for different types of letters symbols, spaces and the final double quotation marks and adds them onto the string
str += ch;
index++;
} else if (isSpecialSymbol(ch)) {
str += ch;
index++;
continue;
} else if (isWhiteSpace(ch)) {
str += ch;
index++;
continue;
} else if (ch == '\"') {
str += ch;
index++;
continue;
}
else break;
}
//string is printed with the line number tokentype and the string itself
System.out.println(linenumber + ", " + TokenType.STRING + ", " + str);
} else {
index++;
continue;
}
}
}
}
To be honest i dont understand your code, so here some simple code.
My Input:
package de;
public class Test {
// Ignore this
/*
ignore this
*/
/*
* Ignore this too
*/
public void hey() {
}
}
My Code:
BufferedReader reader = new BufferedReader(new FileReader("src/test/java/de/Test.java"));
boolean currentlyInComment = false;
String line = reader.readLine();
while (line != null) {
if(line.trim().startsWith("/*")){
currentlyInComment = true;
}
if(!currentlyInComment && !line.trim().startsWith("//")){
// Do your algorithmic stuff with line
System.out.println(line);
}
if(line.trim().startsWith("*/") && currentlyInComment) {
currentlyInComment = false;
}
line = reader.readLine();
}
My Output:
package de;
public class Test {
public void hey() {
}
}
(So implement your code interpretation into this)
What does this do?:
I introduced a variable wether currently there is an comment. You have to set the boolean to false after working with the current line, because this line has to be ignored too.
Basically the programm recognizes comments by "/" and then the end of a comment by "/" and simple single line comments by "//". Every other line will be procceded.

How to use variables in stack?

I'm trying to write a calc program that finds the infix. In addition the user will input numbers for the x variable and the program will solve it. My program works but it only solves it the first time. The following times it gives the same answer as the first time.
import java.util.Scanner;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
class Stack {
char a[] = new char[100];
int top = -1;
void push(char c) {
try {
a[++top] = c;
} catch (StringIndexOutOfBoundsException e) {
System.out.println("Stack full , no room to push , size=100");
System.exit(0);
}
}
char pop() {
return a[top--];
}
boolean isEmpty() {
return (top == -1) ? true : false;
}
char peek() {
return a[top];
}
}
public class intopost {
static Stack operators = new Stack();
public static void main(String argv[]) throws IOException {
String infix;
// create an input stream object
BufferedReader keyboard = new BufferedReader(new InputStreamReader(
System.in));
// get input from user
System.out.print("\nEnter the algebraic expression in infix: ");
infix = keyboard.readLine();
String postFx = toPostfix(infix);
// output as postfix
System.out.println("The expression in postfix is:" + postFx);
if (postFx.contains("x")) {
String line = "";
do {
System.out.println("Enter value of X : ");
line = keyboard.readLine();
if (!"q".equalsIgnoreCase(line)) {
postFx = postFx.replaceAll("x", line);
System.out.println("Answer to expression : "
+ EvaluateString.evaluate(postFx));
}
} while (!line.equals("q"));
} else {
System.out.println("Answer to expression : "
+ EvaluateString.evaluate(postFx));
}
}
private static String toPostfix(String infix)
// converts an infix expression to postfix
{
char symbol;
String postfix = "";
for (int i = 0; i < infix.length(); ++i)
// while there is input to be read
{
symbol = infix.charAt(i);
// if it's an operand, add it to the string
if (symbol != ' ') {
if (Character.isLetter(symbol) || Character.isDigit(symbol))
postfix = postfix + " " + symbol;
else if (symbol == '(')
// push (
{
operators.push(symbol);
} else if (symbol == ')')
// push everything back to (
{
while (operators.peek() != '(') {
postfix = postfix + " " + operators.pop();
}
operators.pop(); // remove '('
} else
// print operators occurring before it that have greater
// precedence
{
while (!operators.isEmpty() && !(operators.peek() == '(')
&& prec(symbol) <= prec(operators.peek()))
postfix = postfix + " " + operators.pop();
operators.push(symbol);
}
}
}
while (!operators.isEmpty())
postfix = postfix + " " + operators.pop();
return postfix.trim();
}
static int prec(char x) {
if (x == '+' || x == '-')
return 1;
if (x == '*' || x == '/' || x == '%')
return 2;
return 0;
}
}
class EvaluateString {
public static int evaluate(String expression) {
char[] tokens = expression.toCharArray();
// Stack for numbers: 'values'
LinkedList<Integer> values = new LinkedList<Integer>();
// Stack for Operators: 'ops'
LinkedList<Character> ops = new LinkedList<Character>();
for (int i = 0; i < tokens.length; i++) {
// Current token is a whitespace, skip it
if (tokens[i] == ' ')
continue;
// Current token is a number, push it to stack for numbers
if (tokens[i] >= '0' && tokens[i] <= '9') {
StringBuffer sbuf = new StringBuffer();
// There may be more than one digits in number
while (i < tokens.length && tokens[i] >= '0'
&& tokens[i] <= '9')
sbuf.append(tokens[i++]);
values.push(Integer.parseInt(sbuf.toString()));
}
// Current token is an opening brace, push it to 'ops'
else if (tokens[i] == '(')
ops.push(tokens[i]);
// Closing brace encountered, solve entire brace
else if (tokens[i] == ')') {
while (ops.peek() != '(')
values.push(applyOp(ops.pop(), values.pop(), values.pop()));
ops.pop();
}
// Current token is an operator.
else if (tokens[i] == '+' || tokens[i] == '-' || tokens[i] == '*'
|| tokens[i] == '/') {
// While top of 'ops' has same or greater precedence to current
// token, which is an operator. Apply operator on top of 'ops'
// to top two elements in values stack
while (!ops.isEmpty() && hasPrecedence(tokens[i], ops.peek()))
values.push(applyOp(ops.pop(), values.pop(), values.pop()));
// Push current token to 'ops'.
ops.push(tokens[i]);
}
}
// Entire expression has been parsed at this point, apply remaining
// ops to remaining values
while (!ops.isEmpty())
values.push(applyOp(ops.pop(), values.pop(), values.pop()));
// Top of 'values' contains result, return it
return values.pop();
}
// Returns true if 'op2' has higher or same precedence as 'op1',
// otherwise returns false.
public static boolean hasPrecedence(char op1, char op2) {
if (op2 == '(' || op2 == ')')
return false;
if ((op1 == '*' || op1 == '/') && (op2 == '+' || op2 == '-'))
return false;
else
return true;
}
// A utility method to apply an operator 'op' on operands 'a'
// and 'b'. Return the result.
public static int applyOp(char op, int b, int a) {
switch (op) {
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a * b;
case '/':
if (b == 0)
throw new UnsupportedOperationException("Cannot divide by zero");
return a / b;
}
return 0;
}
There is a mistake inside while loop in main method. See snippet below.
postFx = postFx.replaceAll("x", line);
System.out.println("Answer to expression : "
+ EvaluateString.evaluate(postFx));
Here postFx = postFx.replaceAll("x", line); you lost reference to postfix form that contains variable x. Subsequent calls of replaceAll doesn't have any effect. So expression with first entered value is evaluated.
You can easily fix it by replacing code above with
System.out.println("Answer to expression : "
+ EvaluateString.evaluate(postFx.replaceAll("x", line)));

Arithmetic calculation for BODMAS in Java

I have written this code for Bodmas, but getting some error in this. If I do 3-5+9, it will result in 3.04.0.
It just start concatenating, though it works for all other operations like *, / and -, please help.
public static String calculation(BODMASCalculation bodmas, String result) {
while (bodmas.hasMatch()) {
double value, leftOfOperator = bodmas.getLeft();
char op = bodmas.getOperator();
double rightOfOprator = bodmas.getRight();
switch (op) {
case '/':
if(rightOfOprator == 0) //Divide by 0 generates Infinity
value = 0;
else
value = leftOfOperator / rightOfOprator;
break;
case '*':
value = leftOfOperator * rightOfOprator;
break;
case '+':
value = leftOfOperator + rightOfOprator;
break;
case '-':
value = leftOfOperator - rightOfOprator;
break;
default:
throw new IllegalArgumentException("Unknown operator.");
}
result = result.substring(0, bodmas.getStart()) + value + result.substring(bodmas.getEnd());
bodmas = new BODMASCalculation(result);
}
return result;
}
Another function is:-
public boolean getMatchFor(String text, char operator) {
String regex = "(-?[\\d\\.]+)(\\x)(-?[\\d\\.]+)";
java.util.regex.Matcher matcher = java.util.regex.Pattern.compile(regex.replace('x', operator)).matcher(text);
if (matcher.find()) {
this.leftOfOperator = Double.parseDouble(matcher.group(1));
this.op = matcher.group(2).charAt(0);
this.rightOfOprator = Double.parseDouble(matcher.group(3));
this.start = matcher.start();
this.end = matcher.end();
return true;
}
return false;
}
I have a solution by adding
String sss = null;
if(op == '+' && !Str.isBlank(result.substring(0, bodmas.getStart())) && value >= 0)
sss = "+";
else
sss = "";
result = result.substring(0, bodmas.getStart()) + sss + value + result.substring(bodmas.getEnd());
But don't want to do that, I want this to work for all the operators.
import java.util.Stack;
public class EvaluateString
{
public static int evaluate(String expression)
{
char[] tokens = expression.toCharArray();
// Stack for numbers: 'values'
Stack<Integer> values = new Stack<Integer>();
// Stack for Operators: 'ops'
Stack<Character> ops = new Stack<Character>();
for (int i = 0; i < tokens.length; i++)
{
// Current token is a whitespace, skip it
if (tokens[i] == ' ')
continue;
// Current token is a number, push it to stack for numbers
if (tokens[i] >= '0' && tokens[i] <= '9')
{
StringBuffer sbuf = new StringBuffer();
// There may be more than one digits in number
while (i < tokens.length && tokens[i] >= '0' && tokens[i] <= '9')
sbuf.append(tokens[i++]);
values.push(Integer.parseInt(sbuf.toString()));
}
// Current token is an opening brace, push it to 'ops'
else if (tokens[i] == '(')
ops.push(tokens[i]);
// Closing brace encountered, solve entire brace
else if (tokens[i] == ')')
{
while (ops.peek() != '(')
values.push(applyOp(ops.pop(), values.pop(), values.pop()));
ops.pop();
}
// Current token is an operator.
else if (tokens[i] == '+' || tokens[i] == '-' ||
tokens[i] == '*' || tokens[i] == '/')
{
// While top of 'ops' has same or greater precedence to current
// token, which is an operator. Apply operator on top of 'ops'
// to top two elements in values stack
while (!ops.empty() && hasPrecedence(tokens[i], ops.peek()))
values.push(applyOp(ops.pop(), values.pop(), values.pop()));
// Push current token to 'ops'.
ops.push(tokens[i]);
}
}
// Entire expression has been parsed at this point, apply remaining
// ops to remaining values
while (!ops.empty())
values.push(applyOp(ops.pop(), values.pop(), values.pop()));
// Top of 'values' contains result, return it
return values.pop();
}
// Returns true if 'op2' has higher or same precedence as 'op1',
// otherwise returns false.
public static boolean hasPrecedence(char op1, char op2)
{
if (op2 == '(' || op2 == ')')
return false;
if ((op1 == '*' || op1 == '/') && (op2 == '+' || op2 == '-'))
return false;
else
return true;
}
// A utility method to apply an operator 'op' on operands 'a'
// and 'b'. Return the result.
public static int applyOp(char op, int b, int a)
{
switch (op)
{
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a * b;
case '/':
if (b == 0)
throw new
UnsupportedOperationException("Cannot divide by zero");
return a / b;
}
return 0;
}
// Driver method to test above methods
public static void main(String[] args)
{
System.out.println(EvaluateString.evaluate("10 + 2 * 6"));
System.out.println(EvaluateString.evaluate("100 * 2 + 12"));
System.out.println(EvaluateString.evaluate("100 * ( 2 + 12 )"));
System.out.println(EvaluateString.evaluate("100 * ( 2 + 12 ) / 14"));
}
}
The Java Scripting API allows you to pass parameters from Java application to the script engine and vice versa.
You can use Javax ScriptEngine to pass values from your app to a script.
And using it's eval() method, you can give it a mathematical expression in the form of a string and it will do the the math for you... (Handles BODMAS too).
Example:
ScriptEngineManager mgr = new.ScriptEngineManager();
ScriptEngine engine = mgr.getEngineByName("JavaScript");
String foo = "40+2/3*45";
System.out.println(engine.eval(foo));
Outputs: 70
Include the following imports , if the IDE doesn't suggest them :
import javax.script.ScriptEngineManager;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
Check the documentation here ScriptEngine
I hope it helps.
The solution can be achieved by using the shunting yard algorithm. We start by creating an infix notation of the equation then follows the postfix notation. Here is a description of the algorithm https://en.wikipedia.org/wiki/Shunting_yard_algorithm. This solution solves for any nested number of brackets on the string expression.
public static double evaluate(String exp) {
char[] tokens = exp.toCharArray();
Queue<Object> values = new LinkedList<>();
// Stack for Operators: 'ops'
Stack<Character> ops = new Stack<Character>();
for (int i = 0; i < tokens.length; i++) {
//infix
// Current token is a whitespace, skip it
if (tokens[i] == ' ') {
continue;
}
// Current token is a number, push it to stack for numbers
else if (tokens[i] >= '0' && tokens[i] <= '9') {
StringBuffer sbuf = new StringBuffer();
// There may be more than one digits in number
while (i < tokens.length && tokens[i] >= '0' && tokens[i] <= '9') {
sbuf.append(tokens[i]);
if ((i+1)<tokens.length &&tokens[i + 1] >= '0' && tokens[i + 1] <= '9') {
i++;
} else {
break;
}
}
values.add(Double.parseDouble(sbuf.toString()));
} else if (tokens[i] == '*' || tokens[i] == '-' || tokens[i] == '/' || tokens[i] == '+') {
if (ops.isEmpty()) {
ops.push(tokens[i]);
continue;
}
char op1 = ops.peek();
boolean hasHighPrecedence = hasPrecedence(op1, tokens[i]);
if (hasHighPrecedence) {
char op = ops.pop();
values.add(op);
ops.push(tokens[i]);
} else {
ops.push(tokens[i]);
}
} else if (tokens[i] == '(') {
ops.push(tokens[i]);
} else if (tokens[i] == ')') {
while (ops.peek() != '(') {
values.add(ops.pop());
}
ops.pop();
}
}
while (!ops.isEmpty()) {
values.add(ops.pop());
}
//post fix
Stack<Double> numStack = new Stack<>();
while (!values.isEmpty()) {
Object val = values.poll();
if (val instanceof Character) {
char v = (Character) val;
if (v == '*' || v == '-' || v == '/' || v == '+') {
double num2, num1;
num1 = numStack.pop();
num2 = numStack.pop();
double ans = applyOp(v, num1, num2);
numStack.push(ans);
}
} else {
double num = (double) val;
numStack.push(num);
}
}
return numStack.pop();
}
public static double applyOp(char op, double b, double a) {
switch (op) {
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a * b;
case '/':
if (b == 0)
throw new
IllegalArgumentException("Cannot divide by zero");
return a / b;
}
return 0;
}
public static boolean hasPrecedence(char op1, char op2) {
if (op1 == '*' && op2 == '/') {
return false;
} else if (op1 == '/' && op2 == '*') {
return true;
} else if ((op1 == '*' || op1 == '/') && (op2 == '+' || op2 == '-')) {
return true;
} else if (op1 == '+' && op2 == '-') {
return true;
} else {
return false;
}
}
"BODMAS" is a not very operational rule. Especially addition and subtraction have the same precedence and are calculated from left to right 1-2+3-4+5 = (((1-2)+3)-4)+5.
The rule is for a nested loop.
Loop
replaceAll ( number ) --> number
replaceAll number `[*/]' number --> number op number
replaceAll number `[+-]' number --> number op number
Until nothing is replaced.
This ensures that 3-4/26+5 -2-> 3-26+5 -2-> 3-12+5 -3-> -9+5 -3-> -4

Undefined char in output of bracket-matching program using custom stack

My Java Program is below. It's my training exercise. The one implements stack stucture for special type of string parsing(string with delimiter).
This delimiter-matching program works by reading characters from the string one at
a time and placing opening delimiters when it finds them, on a stack. When it reads
a closing delimiter from the input, it pops the opening delimiter from the top of the
stack and attempts to match it with the closing delimiter. If they’re not the same
type (there’s an opening brace but a closing parenthesis, for example), an error
occurs. Also, if there is no opening delimiter on the stack to match a closing one, or
if a delimiter has not been matched, an error occurs. A delimiter that hasn’t been
matched is discovered because it remains on the stack after all the characters in the
string have been read.
I use Eclipse. My output is here:
Please enter String:
{}
ch0 = {
ch1 = }
chLabel1 = **UNDEFINED CHAR(SQUARE WITH QUESTION MARK INSIDE IT)**
Error at }**
Could you explain value of chLabel?
As I understand operator "|" (here, cause two operands have boolean type) - is "lazy", shortcut version of "||" operator. I've tested the program after substitution "|" for "||"-result is the same.
public class MyStack {
private int top=0;
private int maxSize=0;
private char[] charArray=null;
public MyStack(int size){
maxSize=size;
top=0;
charArray=new char[maxSize];
}
public void push(char ch){
charArray[top++]=ch;
}
public char pop(){
return charArray[top--];
}
public boolean isEmpty(){
if(top==0)
return true;
else return false;
}
public boolean isFull(){
if(top==(maxSize-1))
return true;
else return false;
}
}
class StringParse {
private String stringForParsing = null;
public StringParse(String string) {
this.stringForParsing = string;
}
public void parser() {
char[] chArr = stringForParsing.toCharArray();
MyStack mySt = new MyStack(chArr.length);
for (int i = 0; i < chArr.length; i++) {
char ch = chArr[i];
switch (ch) {
case '{':
case '(':
case '[':
mySt.push(ch);
System.out.println("ch" + i + " = " + ch);
break;
case '}':
case ')':
case ']':
if (mySt.isEmpty())
System.out.println("Error at" + ch);
else {
char chLabel = mySt.pop();
System.out.println("ch" + i + " = " + ch);
System.out.println("chLabel" + i + " = " + chLabel);
if ((chLabel == '{') && (ch == '}') | (chLabel == '(') && (ch == ')') | (chLabel == '[') && (ch == ']'))
break;
else {
System.out.println("Error at " + ch);
break;
} // end of second else
} //end of first else
default:
break;
} //end of switch
} //end of parser method
}
} //end of class
class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System. in ));
System.out.println("Please enter String:");
String s = br.readLine();
StringParse strP = new StringParse(s);
strP.parser();
}
}
There are two problems:
There's an error with the pop function.
Consider doing one push and then one pop:
top = 0
push
insert at position 0
set top to 1
pop
get position 1 (not set yet!)
set top to 0
You need to use pre-decrement instead of post-decrement, so charArray[top--] should be charArray[--top].
With this change I get chLabel1 = {.
Reiterating what I said in the comments...
| has higher precendence than &&(as opposed to || which has lower precedence) (see this)‌​,
thus a && b | c && d is the same as a && (b | c) && d,
as opposed to a && b || c && d which would be (a && b) || (c && d).
When changing the |'s to ||'s, I no longer get Error at }.
There may be a problem with your MyStack class
Using java.util.Stack gives me no error, just a "chLabel1 = {"
Error at } can be resolved by following Dukeling's advice and using || instead of |:
(chLabel == '{') && (ch == '}') || (chLabel == '(') && (ch == ')') || (chLabel == '[') && (ch == ']')
So, it looks like your code in MyStack.pop() doesn't return a valid char. I'll need to see your MyStack code to help further.

Categories