Infix to Postfix ' StringIndexOutOfBoundsException' error [duplicate] - java

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.

Related

Operator changed to int during infix to postfix conversion

private DSAQueue parseInfixToPostfix(String equation) {
String result = "";
char operator = ' ';
DSAStack stack = new DSAStack();
DSAQueue queue = new DSACircular();
for (int i = 0; i < equation.length(); i++) {
char c = equation.charAt(i);
if (Character.isLetterOrDigit(c)) {
result += c;
}
else if (c == '(') {
stack.push(c);
}
else if (c == ')') {
while (!stack.isEmpty() && stack.top() != '(') {
result += stack.pop();
}
if (!stack.isEmpty() && stack.top() != '(') {
result = "Invalid expression";
}
else {
stack.pop();
}
}
else { //when meets operator
while (!stack.isEmpty() && (precedenceOf(c) <= precedenceOf((char) stack.top()))) {
if (stack.top() == '(') {
result = "Invalid expression";
}
result += stack.pop();
}
stack.push(c);
}
}
while (!stack.isEmpty()) {
if (stack.top() == '(') {
result = "Invalid";
}
result += stack.pop();
}
queue.enqueue(result);
return queue;
}
Above is my code for converting infix to postfix. The example i used is "4+2" and what i got is:
Pushed: 43
Popped: 43
Enqueued: 4243
i dont know why it automatically converted "+" to 43, but i want to store the operator as the operator like "+" in the queue. Is it possible? Or is there an error? because i cant find out what the error is. thank you

How to replace a char in a string without using Replace() in Java?

I've been having trouble with this assignment:
Given a string, replace the first occurrence of 'a' with "x", the second occurrence of 'a' with "xx" and the third occurrence of 'a' with "xxx". After the third occurrence, begin the replacement pattern over again with "x", "xx", "xxx"...etc.; however, if an 'a' is followed by more than 2 other 'a' characters in a row, then do not replace any more 'a' characters after that 'a'.
No use of the replace method is allowed.
aTo123X("ababba") → "xbxxbbxxx"
aTo123X("anaceeacdabnanbag") → "xnxxceexxxcdxbnxxnbxxxg"
aTo123X("aabaaaavfaajaaj") → "xxxbxxxaaavfaajaaj"
aTo123X("pakaaajaaaamnbaa") → "pxkxxxxxxjxxaaamnbaa"
aTo123X("aaaak") → "xaaak"
My code's output is with a's included, x's added but not the correct amount of x's.
public String aTo123X(String str) {
/*
Strategy:
get string length of the code, and create a for loop in order to find each individual part of the String chars.check for a values in string and take in pos of the a.
if one of the characters is a
replace with 1 x, however, there aren't more than 2 a's immediately following first a and as it keeps searching through the index, add more x's to the original string, but set x value back to 1 when x reaches 3.
if one of characters isn't a,
leave as is and continue string.
*/
String xVal = "";
String x = "x";
String output = "";
for (int i = 0; i < str.length(); i++){
if( str.charAt(i) == 'a'){
output += x;
str.substring(i+1, str.length());
}
output += str.charAt(i);
}
return output;
}
This is the code that does the same. I've commented the code to explain what it does
public class ReplaceChar {
public static void main(String... args){
String[] input =new String[]{"ababba","anaceeacdabnanbag","aabaaaavfaajaaj"};
StringBuilder result = new StringBuilder();
for (int i= 0; i < input.length;i++){
result.append(getReplacedA(input[i]));
result.append("\n");
}
System.out.println(result);
}
private static String getReplacedA(String withA){
// stringBuilder for result
StringBuilder replacedString = new StringBuilder();
// counting the number of time char 'a' occurred in String for replacement before row of 'aaa'
int charACount = 0;
// get the first index at which more than two 'aa' occurred in a row
int firstIndexOfAAA = withA.indexOf("aaa") + 1;
// if 'aaa' not occurred no need to add the rest substring
boolean addSubRequired = false;
// if the index is 0 continue till end
if (firstIndexOfAAA == 0)
firstIndexOfAAA = withA.length();
else
addSubRequired = true;
char[] charString = withA.toCharArray();
//Replace character String[] array
String[] replace = new String[]{"x","xx","xxx"};
for(int i = 0; i < firstIndexOfAAA; i++){
if (charString[i] == 'a'){
charACount++;
charACount = charACount > 3 ? 1 : charACount ;
// add the number x based on charCount
replacedString.append(replace[charACount - 1]);
}else{
replacedString.append(charString[i]);
}
}
// if the String 'aaa' has been found previously add the remaining subString
// after that index
if (addSubRequired)
replacedString.append(withA.substring(firstIndexOfAAA));
// return the result
return replacedString.toString();
}
}
Output:
xbxxbbxxx
xnxxceexxxcdxbnxxnbxxxg
xxxbxxxaaavfaajaaj
EDIT : Some Improvement You can make for some corner cases in the getReplacedA() function:
Check if char 'a' is there or not in the String if not just return the String No need to do anything further.
Use IgnoreCase to avoid the uppercase or lowercase possibility.
Firstly, string is immutable, so the below statement does nothing
str.substring(i+1, str.length());
I guess you wanted to do:
str = str.substring(i+1, str.length());
However, even after fix that, your program still doesn't work. I can't really comprehend your solution. 1) you are not detecting more than 3 a's in a row. 2) you are not appending "xx" or "xxx" at all
Here is my version, works for me so far:
public static void main(String[] args) {
System.out.println(aTo123X("ababba")); // "xbxxbbxxx"
System.out.println(aTo123X("anaceeacdabnanbag")); // "xnxxceexxxcdxbnxxnbxxxg"
System.out.println(aTo123X("aabaaaavfaajaaj")); // "xxxbxxxaaavfaajaaj"
}
public static String aTo123X(String str) {
String output = "";
int aOccurrence = 0;
String[] xs = {"x", "xx", "xxx"};
for (int i = 0; i < str.length(); ++i) {
if (str.charAt(i) == 'a') {
output += xs[aOccurrence % 3]; // append the x's depending on the number of a's we have seen, modulus 3 so that it forms a cycle of 3
if (i < str.length() - 3 && str.charAt(i + 1) == 'a' && str.charAt(i + 2) == 'a' && str.charAt(i + 3) == 'a') {//if an 'a' is followed by more than 2 other 'a' characters in a row
output += str.substring(i + 1);
break;
} else {
++aOccurrence; // increment the a's we have encountered so far
}
} else {
output += str.charAt(i); // append the character if it is not a
}
}
return output;
}
public class NewClass {
public static void main(String[] args) {
System.out.println(aTo123X("ababba")); // "xbxxbbxxx"
System.out.println(aTo123X("anaceeacdabnanbag")); // "xnxxceexxxcdxbnxxnbxxxg"
System.out.println(aTo123X("aabaaaavfaajaaj")); //xxxbxxxaaavfaajaaj
}
public static String aTo123X(String str) {
String output = "";
int aCount = 0;
int inRow = 0;
for (int i = 0; i < str.length();) {
if (str.charAt(i) == 'a') {
if (inRow <= 1) {
inRow++;
aCount++;
if (aCount == 1) {
output += "x";
} else if (aCount == 2) {
output += "xx";
} else {
output += "xxx";
aCount = 0;
}
boolean multiple = ((i + 1) < str.length()) && (str.charAt(i + 1) == 'a')
&& ((i + 2) < str.length()) && (str.charAt(i + 2) == 'a');
if (multiple) {
i++;
while (i < str.length()) {
output += str.charAt(i++);
}
return output;
}
} else {
output += str.charAt(i);
}
} else {
output += str.charAt(i);
inRow = 0;
}
i++;
}
return output;
}
}
I am pointing out problems in your code in form of comments in the code itself.
public String aTo123X(String str) {
//You are not using xVal variable in your code, hence it's obsolete
String xVal = "";
//You don't need x variable as you can simply use string concatenation
String x = "x";
String output = "";
for (int i = 0; i < str.length(); i++) {
/**
* Here, in "if" block you have not implmented any logic to replace the 2nd and
* 3rd occurence of 'a' with 'xx' and 'xxx' respectively. Also, substring() returns
* the sub-string of a string but you are not accepting that string anywhere, and
* you need not even use sub-string as "for" loop will cycle through all the
* characters in the string. If use sub-string method you code will only process
* alternative characters.
*/
if( str.charAt(i) == 'a') {
output += x;
str.substring(i+1, str.length());
}
/**
* Because of this statement a's are also returned, because this statement gets
* in both scenarios, whether the current character of string is a or not.
* But, this statement should get executed only when current character of the
* string is 'a'. So, in terms of coding this statement gets executed no matter
* "if" loop is executed or not, but it should get executed only when "if" loop
* is not executed. So, place this statement in else block.
*/
output += str.charAt(i);
}
return output;
}
I have implemented the logic for you. Here is Solution for your problem, just copy and run it. It passes all the specified test cases.
public String aTo123X(String str) {
String output = "";
int count = 1;
boolean flag = true;
for (int i = 0; i < str.length(); i++) {
if(str.charAt(i) == 'a' && flag == true) {
switch(count) {
case 1: output += "x";
count++;
break;
case 2: output += "xx";
count++;
break;
case 3: output += "xxx";
count = 1;
break;
}
if ((str.charAt(i+1) == 'a' && str.charAt(i+2) == 'a') == true) {
flag = false;
}
}
else {
output += str.charAt(i);
}
}
return output;
}
I use Map To store where to replace
public static void main(String[] args) {
System.out.println(aTo123X("ababba"));//xbxxbbxxx
System.out.println(aTo123X("anaceeacdabnanbag"));//xnxxceexxxcdxbnxxnbxxxg
System.out.println(aTo123X("aabaaaavfaajaaj"));//xxxbxxxaaavfaajaaj
}
public static String aTo123X(String str){
String res = "";
int nthReplace = 1; //Integer to store the nth occurence to replace
//Map to store [key == position of 'a' to replace]
//[value == x or xx or xxx]
Map<Integer, String> toReplacePos = new HashMap<>();
//The loop to know which 'a' to replace
for (int i = 0; i < str.length(); i++) {
if(str.charAt(i) == 'a'){
toReplacePos.put(i, nthReplace % 3 == 1 ? "x": (nthReplace % 3 == 2 ? "xx": "xxx"));
nthReplace++;
//Break if an 'a' is followed by more than 2 other 'a'
try {
if((str.charAt(i+1) == 'a')
&& (str.charAt(i+2) == 'a')
&& (str.charAt(i+3) == 'a')){
break;
}
} catch (StringIndexOutOfBoundsException e) {
}
}
}
//Do the replace
for (int i = 0; i < str.length(); i++) {
res += toReplacePos.containsKey(i) ? toReplacePos.get(i) : str.charAt(i);
}
return res;
}
I have edited my answer. This one is giving the correct solution:
public static void main (String[] args) throws InterruptedException, IOException, JSONException {
System.out.println(aTo123X("ababba")); //xbxxbbxxx
System.out.println(aTo123X("anaceeacdabnanbag")); //xnxxceexxxcdxbnxxnbxxxg
System.out.println(aTo123X("aabaaaavfaajaaj")); //xxxbxxxaaavfaajaaj
}
public static String aTo123X(String str) {
String x = "x";
String xx = "xx";
String xxx = "xxx";
int a = 1;
int brek = 0;
String output = "";
for (int i = 0; i < str.length(); i++) {
if(str.charAt(i) == 'a' && a == 1) {
output += x;
str.substring(i+1, str.length());
a = 2;
try {
if(str.charAt(i+1) == 'a' && str.charAt(i+2) == 'a')
brek += 1;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else if(str.charAt(i) == 'a' && a == 2) {
output += xx;
str.substring(i+1, str.length());
a = 3;
try {
if(str.charAt(i+1) == 'a' && str.charAt(i+2) == 'a')
brek += 1;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else if(str.charAt(i) == 'a' && a == 3) {
output += xxx;
str.substring(i+1, str.length());
a = 1;
try {
if(str.charAt(i+1) == 'a' && str.charAt(i+2) == 'a')
brek += 1;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else {
output += str.charAt(i);
brek = 0;
}
if(brek>0) {
output += str.substring(i+1);
break;
}
}
return output;
}

Converting infix to prefix using a Stack (LinkedList)

I am trying to write a method that converts infix to prefix and to do that i want to read a sting reverse and use a stack. When i execute this code i am getting an exception at character = expression.charAt(limit); how can i fix that code?
My input was 1+3 and the error i got was:
Exception in thread "main" java.lang.StringIndexOutOfBoundsException:
String index out of range: 3 at java.lang.String.charAt(Unknown
Source) at PrefixTranslator.translate(PrefixTranslator.java:27) at
PrefixTranslatorTest.main(PrefixTranslatorTest.java:11)
PrefixTranslator Class:
public class PrefixTranslator
{
static private String expression;
private MyStack<Character> stack = new MyStack<Character>();
//Constructor
public PrefixTranslator(String infixExpression)
{
expression = infixExpression;
}//End of constructor
public String translate()
{
//Declare Method Variables
String input = "";
String output = "";
char character = ' ';
char nextCharacter = ' ';
for(int limit = expression.length(); limit > 0 ; limit--)
{
character = expression.charAt(limit);
if(isOperator(character))
{
output = output + character + " ";
}
else if(character == '(')
{
stack.push(character);
}
else if(character == ')')
{
while(!stack.top().equals('('))
output = output + stack.pop() + " ";
stack.pop();
}
else
{
if(Character.isDigit(character) && (limit + 1) < limit && Character.isDigit(expression.charAt(limit+1)))
{
stack.push(character);
stack.push(expression.charAt(limit+1));
}
else if(Character.isDigit(character))
{
stack.push(character);
}
else
{
output = output + character;
}
}
}//End of for
while(!stack.isEmpty())
{
output = output + stack.pop() + " ";
}
return output;
}//End of translate method
//Check priority on characters
public static int precedence(char operator)
{
if(operator == '+' || operator =='-')
return 1;
else if(operator == '*' || operator == '/')
return 2;
else
return 0;
}//End of priority method
public boolean isOperator(char element)
{
if(element == '*' || element == '-' || element == '/' || element == '+')
return true;
else
return false;
}//End of isOperator method
}//End of class
PrefixTranslatorTest Class:
import java.util.Scanner;
public class PrefixTranslatorTest{
public static void main(String[] args)
{
Scanner input = new Scanner(System.in);
System.out.println("Enter the expression that you want to convert to prefix.");
String expression = input.next();
PrefixTranslator translator = new PrefixTranslator(expression);
System.out.println(translator.translate());
}
}
For the given input 1+3 expression.length() returns 3 and you can refer to indexes 0-2 of that string. So, your loop shouldn't be:
for(int limit = expression.length(); limit > 0 ; limit--)
And it should be
for(int limit = expression.length() - 1; limit >= 0 ; limit--)
The first index of Java arrays is 0 and the method length() returns the number of elements of array. If you need the last element's index, use
length() - 1.
So instead of
for (int limit = expression.length(); limit > 0; limit--)
use
for (int limit = expression.length() - 1; limit >= 0; limit--)

Java StringTokenizer considering parentheses

I am creating a program that tokenizes boolean logic expressions and returns the String array of tokens. The following is my code:
public static String[] tokenize(String s)
{
String delims = "+";
StringTokenizer st = new StringTokenizer(s, delims);
String[] tokens = new String[st.countTokens()];
int i=0;
while (st.hasMoreElements()) {
tokens[i++] = st.nextElement().toString();
}
return tokens;
}
For example, I have the following string as an input:
A+B+(C+D+(A+B))+(B+C)
Using the code I have, it will only generate the following tokens:
A
B
(C
D
(A
B))
(B
C)
Is it possible (using the same structure of code) to come up with these tokens? If not, how is it code-able?
A
B
(C+D+(A+B))
(B+C)
ArrayList<String> tokens = new ArrayList<String>();
String current = "";
int counter = 0;
for(int i = 0 ; i < input.length(); i++)
{
char c = input.charAt(i);
if(counter==0 && c=='+')
{
tokens.add(current);
current = "";
continue;
}
else if(c=='(')
{
counter++;
}
else if(c==')')
{
counter--;
}
current += c;
}
tokens.add(current);
This is the solution for my comment:
You could just loop through 1 character at a time, when you reach a +
while not in a parenthesis, save the characters read up to there, and
start a new set. The way to track if you're in a a set of parentheses
is with a counter. When you hit a open parenthesis, you increment a
counter by 1, when you hit a close parenthesis you decrement the
counter by 1. If the counter > 0 then you're in parentheses. Oh, and
if counter ever goes negative, the string is invalid, and if counter
is not 0 at the end, then the string is also invalid.
You can do the checks on counter and return false or something, to show that it is an invalid string. If you know the string is valid then this works as is. You can get an array from the ArrayList, with tokens.toArray()
If you can find a simple solution go with it otherwise try mine
String s = "A+B+(C+D+(A+B))+(B+C)";
List<String> l = new ArrayList<>();
StringBuilder sb = new StringBuilder();
int p = 0;
for (char c : s.toCharArray()) {
if (c == '(') {
p++;
sb.append(c);
} else if (c == ')') {
p--;
sb.append(c);
} else if (p == 0 && c == '+') {
l.add(sb.toString());
sb.setLength(0);
} else {
sb.append(c);
}
}
if (sb.length() > 0) {
l.add(sb.toString());
}
System.out.println(l);
output
[A, B, (C+D+(A+B))]

Reading in text file gives ArrayIndexOutOfBoundsException

I am attempting to read this .txt file into my program (as an improvement over manual input) and i am having trouble converting my methods to accept the input txt file. i get a arrayindexoutofboundsexception on line "infix[--pos]='\0';"
class Functions {
void postfix(char infix[], char post[]) {
int position, und = 1;
int outposition = 0;
char topsymb = '+';
char symb;
Stack opstk = new Stack();
opstk.top = -1;
for (position = 0; (symb = infix[position]) != '\0'; position++) {
if (isoperand(symb))
post[outposition++] = symb;
else {
if (opstk.isempty() == 1)
und = 1;
else {
und = 0;
topsymb = opstk.pop();
}
while (und == 0 && precedence(topsymb, symb) == 1) {
post[outposition++] = topsymb;
if (opstk.isempty() == 1)
und = 1;
else {
und = 0;
topsymb = opstk.pop();
}
}// end while
if (und == 0)
opstk.push(topsymb);
if (und == 1 || (symb != ')'))
opstk.push(symb);
else
topsymb = opstk.pop();
}// end else
}// end for
while (opstk.isempty() == 0)
post[outposition++] = opstk.pop();
post[outposition] = '\0';
}// end postfix function
int precedence(char topsymb, char symb) {
/* check precedence and return 0 or 1 */
if (topsymb == '(')
return 0;
if (symb == '(')
return 0;
if (symb == ')')
return 1;
if (topsymb == '$' && symb == '$')
return 0;
if (topsymb == '$' && symb != '$')
return 1;
if (topsymb != '$' && symb == '$')
return 0;
if ((topsymb == '*' || topsymb == '/') && (symb != '$'))
return 1;
if ((topsymb == '+' || topsymb == '-') && (symb == '-' || symb == '+'))
return 1;
if ((topsymb == '+' || topsymb == '-') && (symb == '*' || symb == '/'))
return 0;
return 1;
} /* end precedence function */
private boolean isoperand(char symb) {
/* Return 1 if symbol is digit and 0 otherwise */
if (symb >= '0' && symb <= '9')
return true;
else
return false;
}/* end isoperand function */
}
public class Driver {
public static void main(String[] args) throws IOException {
Functions f = new Functions();
char infix[] = new char[80];
char post[] = new char[80];
int pos = 0;
char c;
System.out.println("\nEnter an expression is infix form : ");
try {
BufferedReader in = new BufferedReader(new FileReader("infix.txt"));
String str;
while ((str = in.readLine()) != null) {
infix = str.toCharArray();
}
in.close();
} catch (IOException e) {
}
infix[--pos] = '\0';
System.out.println("The original infix expression is : ");
for (int i = 0; i < pos; i++)
System.out.print(infix[i]);
f.postfix(infix, post);
System.out.println("\nThe postfix expression is : ");
for (int i = 0; post[i] != '\0'; i++)
System.out.println(post[i]);
}
}
Do should never ever do like this:
try {
...
} catch (IOException e) {
}
You loose some essential information about your code-running.
At lease you should print the stack trace to follow the investigation:
e.printStackTrace();
You may have a FileNotFound exception.
In addition you try to index your array to -1 in infix[--pos], pos is set to 0 before this statement.
1) Totally aside, but I think line in main should read:System.out.println("\nEnter an expression in infix form : ");
2) As well, i agree about the catch statement. You already have narrowed it down to being an IOExcpetion, but you can find so much more info out by printing wither of the following inside the catch
System.err.println(e.getMessage()); or e.printStackTrace()
Now to answer your question. You are initializing pos to the value 0, but the you are doing a PREINCREMENT on the line infix[--pos] = '\0'; so pos becomes -1 (clearly outside the scope of the array bounddaries).
I think you want to change that to a post increment infix[pos--] = '\0';. Perhaps?
And yes, your code DOES Look like C...

Categories

Resources