Infix to Postfix using stacks and Precedence of Operators [duplicate] - java

This question already has answers here:
Handling parenthesis while converting infix expressions to postfix expressions
(2 answers)
Closed 5 years ago.
I know there are similar questions to this already on SO but I can't find one which solves the problem I'm having. I am trying to make a method which converts infix notation expressions to postfix notation, while implementing precedence of operators in order to get correct output.
I have made my own stack class with the usual methods (push, pop, peek etc.) and it works absolutely fine. My problem is that for more complicated expressions such as A-(B+C^D^C)/D*B , I am getting the wrong output. The result of the conversion should be ABCDC^^+D/B*- whereas i keep on getting ABCDC^^+D/-B
here is my method:
public static String infixToPostfix(char[] expressionArray, CharStack opStack){
String output = "";
int length = expressionArray.length;
for(int i = 0; i < length; i++){
if(isOperatorOrBracket(expressionArray[i])){
if(priorityAtInput(expressionArray[i]) >= priorityAtStack(opStack.peek())){
opStack.push(expressionArray[i]);
}else if(priorityAtInput(expressionArray[i]) == priorityAtStack(opStack.peek())){
output = output + expressionArray[i];
}else{
while(opStack.peek() != '('){
output = output + opStack.pop();
}
opStack.pop();
}
}else{
output = output + expressionArray[i];
}
}
while(!opStack.empty()){
if(opStack.peek() != '('){
output = output + opStack.pop();
}else if(opStack.peek() == '('){
opStack.pop();
}
}
return output;
}
Please let me know if you need to any of the component methods. Any help greatly appreciated!

After an hour of staring at the screen I found the problem. Thank goodness for the debugger in eclipse!
public static String infixToPostfix(char[] expressionArray, CharStack opStack){
String output = "";
int length = expressionArray.length;
for(int i = 0; i < length; i++){
if(isOperatorOrBracket(expressionArray[i])){
if(priorityAtInput(expressionArray[i]) >= priorityAtStack(opStack.peek())){
opStack.push(expressionArray[i]);
}else if(priorityAtInput(expressionArray[i]) < priorityAtStack(opStack.peek())){
while(priorityAtInput(expressionArray[i]) < priorityAtStack(opStack.peek())){
output = output + opStack.pop();
if(opStack.peek() == '('){
opStack.pop();
break;
}else if(priorityAtInput(expressionArray[i]) >= priorityAtStack(opStack.peek())){
opStack.push(expressionArray[i]);
break;
}
}
}else{
while(opStack.peek() != '('){
output = output + opStack.pop();
}
opStack.pop();
}
}else{
output = output + expressionArray[i];
}
}
while(!opStack.empty()){
if(opStack.peek() != '('){
output = output + opStack.pop();
}else if(opStack.peek() == '('){
opStack.pop();
}
}
return output;
}

Related

illegal start of expression error but i have all my curly braces [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
public String starOut(String str) {
int i = 0;
while(i <= str.length()-2){
if(str.substring(i, i+1).equals(*) && i < 2){
str = str.substring(i+2);
}
else if(str.substring(i, i+1).equals("*")){
str = str.substring(i-2, i-1)+ str.substring(i+2);
}
i++
}
return str;
}
I get an error saying "missing '}' or illegal start of expression" but I have all of the curly braces I think. Help!
You forgot double quotes around "*" (Line 3) and semicolon after i++ (Line 9).
public String starOut(String str) {
int i = 0;
while(i <= str.length()-2) {
if(str.substring(i, i+1).equals("*") && i < 2) {
str = str.substring(i+2);
}
else if(str.substring(i, i+1).equals("*")) {
str = str.substring(i-2, i-1)+ str.substring(i+2);
}
i++;
}
return str;
}
I also recommend using charAt instead of doing substrings to retrieve characters at particular positions.
So at the end it will look like this:
public String starOut(String str) {
int i = 0;
while(i <= str.length() - 2){
if(str.charAt(i) == '*' && i < 2){
str = str.substring(i + 2);
}
else if(str.charAt(i) == '*'){
str = str.charAt(i - 2) + str.substring(i + 2);
}
i++;
}
return str;
}

Infix to Postfix ' StringIndexOutOfBoundsException' error [duplicate]

This question already has an answer here:
What is a StringIndexOutOfBoundsException? How can I fix it?
(1 answer)
Closed 3 years ago.
I am setting up a method that turn a infix string into a postfix equation with a custom LinkStack.
I have tried to to check if the charAt(i) was null and a if statement to check if i is greater than exp.length() but neither worked.
public static String infixToPostfix(String exp)
{
// make variable
String result = new String("");
int temp = 0;
LinkedStack stack = new LinkedStack();
for (int i = 0; i<exp.length(); ++i)
{
char c = exp.charAt(i);
if(Character.isDigit(c))
{
int n = 0;
//extract the characters and store it in num
while(Character.isDigit(c))
{
n = n*10 + (int)(c-'0');
i++;
c = exp.charAt(i); //exception occurs
System.out.println(n);
}
i--;
//push the number in stack
stack.push(n);
//System.out.println(stack.size() + ", Stack size");
}
// If ( push it to the stack.
if (c == '(')
stack.push(c);
// If ) pop and output from the stack
// until an '(' is encountered.
else if (c == ')')
{
while (!stack.isEmpty() && stack.peek() != '(')
result += stack.pop();
if (!stack.isEmpty() && stack.peek() != '(')
return "Invalid Expression"; // invalid expression
else
stack.pop();
}
else // an operator is encountered
{
while (!stack.isEmpty() && pre(c) <= pre((char) stack.peek()))
result += stack.pop();
stack.push(c);
}
}
// pop all the operators from the stack
while (!stack.isEmpty())
result += stack.pop();
String temp2 = stack.print();
System.out.println(temp2);
return result;
}
I expect the output to be 469 645 + if the input is 496+645 but the actual output is java.lang.StringIndexOutOfBoundsException: String index out of range: 7.
while(Character.isDigit(c))
{
n = n*10 + (int)(c-'0');
i++;
c = exp.charAt(i); //exception occurs
System.out.println(n);
}
You aren't length checking here, so you readily parse right off the end of the string.
while(i < exp.length() && Character.isDigit(c))
{
n = n*10 + (int)(c-'0');
if (++i < exp.length()) {
c = exp.charAt(i); //exception occurs
}
System.out.println(n);
}
Note: I'd cache the length because of how many times you use it, but that's not the cause of your problem.
Note, however, that this is cleaner code style:
public class Foo {
public static void main(String[] args) {
String myString = "12345";
int index = 0;
for (char c: myString.toCharArray()) {
System.out.printf("Char at %d == %c\n", index, c);
++index;
}
}
}
Notice the for-loop. I didn't do your calculations or break out or anything, but this is a cleaner way.
You can also do...
for (int index = 0; index < exp.length(); ++index) {
char c = exp.charAt(index);
if (!Character.isDigit(c)) {
break;
}
// Do other stuff here.
}
There are a variety of other ways to structure your code. Your while loop is awkward.

How to Match Parenthesis to Parse a S-Expression?

I am trying to create a function that does the following:
Assuming that the code input is "(a 1 2 (b 3 4 5 (c 6) |7) 8 9)"
where the pipe | symbol is the position of the cursor,
the function returns:
a String "b 3 4 5 (c 6) 7" representing the code that is in the scope of the cursor
an int 8 representing the start index of the string relative to the input
an int 30 representing the end index of the string relative to the input
I already have working code that returns exactly that. However, the problem lies in ignoring comments, while keeping track of context (e.g. String literals, my own literal delimiters, etc).
Here is the code which keeps track of context:
public static void applyContext(Context context, String s, String snext, String sprev) {
if (s.equals("\"")) {
if (context.context == Context.Contexts.MAIN) {
context.context = Context.Contexts.STRING;
context.stringDelimiterIsADoubleQuote = true;
} else if (context.context == Context.Contexts.STRING && context.stringDelimiterIsADoubleQuote && !sprev.equals("\\"))
context.context = Context.Contexts.MAIN;
} else if (s.equals("\'")) {
if (context.context == Context.Contexts.MAIN) {
context.context = Context.Contexts.STRING;
context.stringDelimiterIsADoubleQuote = false;
} else if (context.context == Context.Contexts.STRING && !context.stringDelimiterIsADoubleQuote && !sprev.equals("\""))
context.context = Context.Contexts.MAIN;
} else if (s.equals("/") && snext.equals("/")) {
if (context.context == Context.Contexts.MAIN)
context.context = Context.Contexts.COMMENT;
} else if (s.equals("\n")) {
if(context.context == Context.Contexts.COMMENT)
context.context = Context.Contexts.MAIN;
}
else if (s.equals("\\")) {
if(context.context == Context.Contexts.MAIN)
context.context = Context.Contexts.PATTERN;
else if(context.context == Context.Contexts.PATTERN)
context.context = Context.Contexts.MAIN;
}
}
Firstly, I'll be using the function above like so:
String sampleCode = "(a b "cdef" g \c4 bb2 eb4 g4v0.75\)";
Context c = new Context(Context.Contexts.MAIN);
for(int i = 0; i < sampleCode.length(); i++) {
String s = String.valueOf(sampleCode.charAt(i));
String snext = *nullcheck* ? String.valueOf(sampleCode.charAt(i + 1)) : "";
String sprev = *nullcheck* ? String.valueOf(sampleCode.charAt(i - 1)) : "";
applyContext(c, s, snext, sprev);
if(c.context == blahlbah) doBlah();
}
Second, I'll be using this both forwards an backwards, as the current method of doing the function stated at the top of the description is (in pseudocode) this:
function returnCodeInScopeOfCursor(theWholeCode::String, cursorIndex::int) {
var depthOfCodeAtCursorPosition::int = getDepth(theWholeCode, cursorIndex);
Context c = new Context(getContextAt(theWholeCode, cursorIndex));
var currDepth::int = depthOfCodeAtCursorPosition;
var startIndex::int, endIndex::int;
for(i = cursorIndex; i >= 0; i--) {//going backwards
s = .....
snext = ......
sprev = ......
applyContext(c, s, snext, sprev);
if(c.context == Context.MAIN) {
if s = "(" then currDepth --;
if s = ")" then currDepth ++;
}
when currDepth < depthOfCodeAtCursorPosition
startIndex = i + 1;
break;
}
currDepth = depthOfCodeAtCursorPosition;//reset
for(i = cursorIndex; i < theWholeCode.length; i++) {//going forwards
s = ...
snex......
sprev.....
applyContext(c, s, snext, sprev);
if(c.context == Context.MAIN) {
if s = "(" then currDepth ++;
if s = ")" then currDepth --;
}
when currDepth < depthOfCodeAtCursorPosition
endIndex = i - 1;
break;
}
var returnedStr = theWholeCode->from startIndex->to endIndex
return new IndexedCode(returnedStr, startIndex, endIndex);
As you can see, this function would work both forwards and in reverse. Or at least most of it. The only problem is that if I were to use this function backwards, the proper scanning of comments (denoted by the standard ECMA double slash "//") goes haywire.
If I were to create a separate function for reverse context application and check every line recursively for a double slash, then making everything after that '//' a COMMENT (or in the direction of the function's usage, everything before that //), it will take way too much processing time as I want to use this as a livecoding environment for music.
Also, removing the comments before trying to do that returnCodeInScopeOfCursor method may not be feasible... as I need to keep track of the indexes of the code and what not. If I were to remove the comments, there will be a big mess with all the code positions and keeping track of where did I remove what exactly and how many characters etc....
The text area input GUI I'm working with (RichTextFX) does not support Line-Char tracking, so everything is tracked using char index only, hence the problems...
So... I'm utterly perplexed as with what to do with my current code. Any help, suggestions, advice etc... will be greatly appreciated.
Could you pre-transform comments from // This is a comment<CR> to { This is a comment}<CR> you then have a language you can walk backwards and forwards.
Apply this transform on the way in and reverse it on the way out and all should be well. Notice we are replacing //... with {...} so all charaqcter offsets are retained.
Anyways, after a little experimenting with OldCurmudgeon's idea, I came up with a separate function to get context of the code in a reverse direction.
public static void applyContextBackwards(Context context, String entireCode, int caretPos) {
String s = String.valueOf(entireCode.charAt(caretPos));
//So far this is not used
//String snext = caretPos + 1 < entireCode.length() ? String.valueOf(entireCode.charAt(caretPos + 1)) : "";
String sprev = caretPos - 1 >= 0 ? String.valueOf(entireCode.charAt(caretPos - 1)) : "";
//Check for all the flags and what not...
if(context.commentedCharsLeft > 0) {
context.commentedCharsLeft--;
if(context.commentedCharsLeft == 0)
context.context = Context.Contexts.MAIN;//The comment is over
}
if(context.expectingEndOfString){
context.context = Context.Contexts.MAIN;
context.expectingEndOfString = false;
}
if(context.expectingEndOfPattern) {
context.context = Context.Contexts.MAIN;
context.expectingEndOfPattern = false;
}
//After all the flags are cleared, do this
if(context.commentedCharsLeft == 0) {
if (s.equals("\"")) {
if (context.context == Context.Contexts.MAIN) {
context.context = Context.Contexts.STRING;
context.stringDelimiterIsADoubleQuote = true;
} else if (context.context == Context.Contexts.STRING && context.stringDelimiterIsADoubleQuote && !sprev.equals("\\"))
context.expectingEndOfString = true;//Change the next char to a MAIN, cuz this one's still part of the string
} else if (s.equals("\'")) {
if (context.context == Context.Contexts.MAIN) {
context.context = Context.Contexts.STRING;
context.stringDelimiterIsADoubleQuote = false;
} else if (context.context == Context.Contexts.STRING && !context.stringDelimiterIsADoubleQuote && !sprev.equals("\""))
context.expectingEndOfString = true;//Change the next char to a MAIN, cuz this one's still part of the string
} else if (s.equals("\n")) {
int earliestOccuranceOfSingleLineCommentDelimiterAsDistanceFromThisNewLine = -1;//-1 for no comments
//Loop until the next \n is found. In the process, determine location of comment if any
for(int i = caretPos; i >= 0; i--) {
String curr = String.valueOf(entireCode.charAt(i));
String prev = i - 1 >= 0 ? String.valueOf(entireCode.charAt(i - 1)) : "";
if(curr.equals("\n"))
break;//Line has been scanned through
if(curr.equals("/") && prev.equals("/"))
earliestOccuranceOfSingleLineCommentDelimiterAsDistanceFromThisNewLine = caretPos - i;
}
//Set the comment context flag
//If no comments, -1 + 1 will be 0 and will be treated as no comments.
context.commentedCharsLeft = earliestOccuranceOfSingleLineCommentDelimiterAsDistanceFromThisNewLine + 1;
if(earliestOccuranceOfSingleLineCommentDelimiterAsDistanceFromThisNewLine > 0) {
context.context = Context.Contexts.COMMENT;
}
} else if (s.equals("\\")) {
if (context.context == Context.Contexts.MAIN)
context.context = Context.Contexts.PATTERN;
else if (context.context == Context.Contexts.PATTERN)
context.expectingEndOfPattern = true;//Change the next char to a MAIN cuz this one's still part of the Pattern
}
}
}

What is happening here when the else statement is not used?

This is coding bat exercise: Java > Warmup-2 > stringX
What is the second block of code doing? Why does it produce the wrong answer?
public String stringX(String str) {
String answer = "";
for (int i = 0; i < str.length(); i++) {
if (str.substring(i , i+1).equals("x") && i != 0 && i != str.length()-1) {
answer = answer + "";
}
else {
answer = answer + str.substring(i , i + 1);
}
}
return answer;
}
vs
public String stringX(String str) {
String answer = "";
for (int i = 0; i < str.length(); i++) {
if (str.substring(i , i+1).equals("x") && i != 0 && i != str.length()-1) {
answer = answer + "";
}
answer = answer + str.substring(i , i + 1);
}
return answer;
}
The first block will run else only if the first if statement is false. else statement can only run if none of the above conditional statements returned true (if and else if). However the second block will run regardless of whether the first if statement true or false.
Check out this doc for further explanation: https://docs.oracle.com/javase/tutorial/java/nutsandbolts/if.html
The 2nd block executes all the code shown and thus always takes the substring of answer

Else if condition being ignored?

I'm new to Java and i have to make a small application that will calculate GCD of up to 5 numbers.
If the input is nothing before 5 numbers have been entered, the application will calculate it on the already given numbers
Unfortunately my code seems to ignore my else if statement that will make sure it doesn't try to add "" to a int array.
This is the part that i am struggling on, i have already tried contains instead of equals but with no result.
Am i writing the !input.. wrong? The code runs correct when i try to add a 0, it will not execute the else if.
But if i enter "" to make the application run the first part of the if statement it will go to the else if after its done and try to add "" to the array which of course results in an error.
I'm sure its something small i am missing or am unaware of, but i can't seem to figure it out.
}else if(Integer.parseInt(input) != 0 || !input.equals(""));{
ggdGetallen[count] = Integer.parseInt(input);
count++;
txtGetal.selectAll();
}
Full code
private void txtGetalActionPerformed(java.awt.event.ActionEvent evt) {
String input = txtGetal.getText();
//Berekenen van het kleinste getal in het array
if(count > 4 || input.equals("")){
int kleinsteGetal = ggdGetallen[0];
for (int getal : ggdGetallen){
if (getal < kleinsteGetal && getal != 0){
kleinsteGetal = getal;
}
}
boolean isDividableBy;
boolean ggdFound = false;
while(!ggdFound){
for (int getal : ggdGetallen) {
if (getal != 0){
isDividableBy = (getal % kleinsteGetal == 0);
ggdFound = true;
if(!isDividableBy){
kleinsteGetal--;
ggdFound = false;
break;
}
}
}
}
lblResultaat.setText(String.format("De grootste gemene deler is %d", kleinsteGetal));
}else if(Integer.parseInt(input) != 0 || !input.equals(""));{
ggdGetallen[count] = Integer.parseInt(input);
count++;
txtGetal.selectAll();
}
}
remove semicolon from your else if.

Categories

Resources