I wrote this code to recursively evaluate an expression (I'm not done, just working my way up to brackets and parentheses) and I just completed my recursion for the multiplication/division/addition/subtraction. I'm getting a StringOutOfBoundsException for String sub1 = s.substring(0,i);, any ideas why? I put some print statements in to check the value of i, and it never came as a value that was not possible for a string index, so what is my problem?
public float evaluate() {
String s = expr;
float answer = 0;
//one single variable or just a number
if(s.contains("+") == false && s.contains("-") == false && s.contains("*") == false && s.contains("/") == false && s.contains("[") == false &&s.contains("]") == false && s.contains("(") == false && s.contains(")") == false){
if(scalars.size() == 0){
answer = Float.parseFloat(s);
return answer;
}
answer = this.scalars.get(0).value;
System.out.println("one var/number loop");
return answer;
}
//no parentheses/brackets
if(s.contains("(") == false && s.contains(")") == false && s.contains("[") == false && s.contains("]") == false && (s.contains("+") == true || s.contains("-") == true || s.contains("*") == true || s.contains("/") == true)){
answer = evalNoPB(s);
System.out.println("no parens loop");
return answer;
}
//make compiler happy
System.out.println("no loop");
return 0;
}
private float evalNoPB(String s){
float tempAns = 0;
if(s.contains("(") == false && s.contains(")") == false && s.contains("[") == false && s.contains("]") == false){
int i;
for(i=s.length()-1; i>=0; i--){
if(s.charAt(i) == '+' || s.charAt(i) == '-'){
System.out.println(i);
break; // keep value of i for substrings
}
} if (i<0) { // for loop went through and did not find + or -
for(i=s.length()-1; i>=0; i--){
if(s.charAt(i) == '*' || s.charAt(i) == '/'){
System.out.println(i);
break; // keep value of i for substrings
}
}
}
String sub1 = s.substring(0,i);
String sub2 = s.substring(i+1, s.length());
if(s.charAt(i) == '+'){
tempAns = evalNoPB(sub1) + evalNoPB(sub2);
} else if(s.charAt(i) == '-'){
tempAns = evalNoPB(sub1) - evalNoPB(sub2);
}else if(s.charAt(i) == '*'){
tempAns = evalNoPB(sub1) * evalNoPB(sub2);
}else if (s.charAt(i) == '/'){
float divisorCheck = evalNoPB(sub2);
if(divisorCheck!= 0){
tempAns = evalNoPB(sub1) / evalNoPB(sub2);
}else { // cannot divide by 0
throw new IllegalArgumentException("cannot divide by 0");
}
}
}
return tempAns;
}
test
Enter the expression, or hit return to quit => 3*3
1 (this is the i value)
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String
index out of range: -1
at java.lang.String.substring(Unknown Source)
at apps.Expression.evalNoPB(Expression.java:306)
at apps.Expression.evalNoPB(Expression.java:314)
at apps.Expression.evaluate(Expression.java:280)
at apps.Evaluator.main(Evaluator.java:36)
for(i=s.length()-1; i>=0; i--){
if(s.charAt(i) == '*' || s.charAt(i) == '/'){
System.out.println(i);
break; // keep value of i for substrings
}
}
In this code segment variable i eventually become -1 and continue to execute.
Even though actual design should be changed, for this step, just adding another if statement, just after for statement will solve the situation.
if (i < 0) { // for loop went through and did not find + or -
for (i = s.length() - 1; i >= 0; i--) {
if (s.charAt(i) == '*' || s.charAt(i) == '/') {
System.out.println(i);
break; // keep value of i for substrings
}
}
}
if(i < 0)
return tempAns;
String sub1 = s.substring(0, i);
But only this situation, you will have other problems.
Related
I have been trying to figure out how to detect where and what error occurred in a regular infix expression. The first thing that I came up with looks like this...
String expression = "(12 * 12) + (12 * 9)";
int numOfDigits = 0;
int numOfOperators = 0;
boolean onDigit = false;
for (int i = 0; i < expression.length(); i++) {
char ch = expression.charAt(i);
if (Character.isDigit(ch) && !onDigit) {
numOfDigits += 1;
onDigit = true;
} else if (ch == '+' || ch == '-' || ch == '/' || ch == '*') {
numOfOperators += 1;
onDigit = false;
} else if (Character.isWhitespace(ch)) {
onDigit = false;
}
}
if (numOfDigits - 1 != numOfOperators) {
System.out.println("Missing operand(s) or operator(s) in expression");
}
The only issue with this is that I can't detect where in the expression the error is coming from. At this point, I decided to go with something that looks like this as it can detect where in the string the error is coming from. The only problem that I am having with it is that if there is an operator at the end of the string I can't figure out how to allow the program to detect that and display an error. Any help would be greatly appreciated.
for (int i = 0; i < expression.length(); i++) {
char ch = expression.charAt(i);
if (lastType.equalsIgnoreCase("") && (ch == '+' || ch == '-' || ch == '/' || ch == '*')) {
System.out.printf("Missing operand at: %d\n", lastLocation + 1);
break;
}
if (Character.isDigit(ch)) {
if (!onDigit) {
if (lastType.equalsIgnoreCase("digit")) {
System.out.printf("Missing operator at: %d\n", lastLocation + lenOfDigit);
break;
}
lastType = "Digit";
lastLocation = i + 1;
numOfDigits += 1;
onDigit = true;
}
lenOfDigit++;
} else if (ch == '+' || ch == '-' || ch == '/' || ch == '*') {
if (lastType.equalsIgnoreCase("operator")) {
System.out.printf("Missing operand at: %d\n", lastLocation + 1);
break;
}
lastType = "Operator";
lastLocation = i + 1;
numOfOperators += 1;
onDigit = false;
lenOfDigit = 0;
} else if (Character.isWhitespace(ch)) {
onDigit = false;
}
}
You can traverse the string backwards and find the first index where Character.isDigit() is true. Then simultaneously find the first index where the character is an operator. If the index for the operator is larger than the index for the digit, then you've found the discrepancy where an operator is the last character in the expression.
EDIT:
I'm assuming you want to detect when an expression has an operator that is not followed by any digit.
Eg: "(12 * 12) + (12 * 9) +"
You could detect this with:
int lastDigitIndex = -1;
int lastOperatorIndex = -1;
for (int i = expression.length()-1; i >= 0; --i)
{
char ch = expression.charAt(i);
if (Character.isDigit(ch) && lastDigitIndex == -1)
lastDigitIndex = i;
else if((ch == '+' || ch == '-' || ch == '/' || ch == '*') && lastOperatorIndex == -1)
lastOperatorIndex = i;
if (lastDigitIndex != -1 && lastOperatorIndex != -1)
break;
}
if (lastOperatorIndex > lastDigitIndex)
{
//Error found
}
I'm writing a program for class, that as the title says, evaluates infix expressions of unsigned integers using two stacks. The division should be integer division which is why the numbers are integers and not Double. I have created a GUI that gets input from the user and should return the answer. I have attached an ActionListener to the button to compute using this code:
result = Evaluate.evalExp(txtExp.getText());
txtResult.setText(result + "");
The problem is that when I run the program I don't get the correct answer.
For 3-4 I'll get 3, for 6/2 I get 2, and for anything that has parenthesis I get 0 for the answer. I have been trying to figure this out for the better part of the day without any results. I'm hoping someone here will be able to help.
import java.util.Stack;
public class Evaluate {
public static int evalExp(String input) {
char[] tokens = input.toCharArray();
Stack<Integer> number = new Stack<Integer>();
Stack<Character> operator = new Stack<Character>();
int holder = 0;
int ans;
for (int i=0; i < tokens.length; i++) {
// checking to see if token is a number
if (tokens[i] >= '0' && tokens[i] <= '9') {
StringBuffer num = new StringBuffer();
// need to check if number is more than one digit long
while ( i < tokens.length && tokens[i] >= '0' && tokens[i] <= '9')
num.append(tokens[i++]);
number.push(Integer.parseInt(num.toString()));
}
else if (tokens[i] == '(')
operator.push(tokens[i]);
else if (tokens[i] == ')') {
while (operator.peek() != '(') {
holder = applyOp(operator.pop(), number.pop(), number.pop());
number.push(holder);
}
operator.pop();
}
else if (tokens[i] == '+' || tokens[i] == '-' || tokens[i] == '*' || tokens[i] == '/') {
// check for precedence
while (!operator.empty() && hasPrecedence(tokens[i], operator.peek())) {
holder = applyOp(operator.pop(), number.pop(), number.pop());
number.push(holder);
}
operator.push(tokens[i]);
}
} // end for loop
while (!operator.empty()) {
holder = applyOp(operator.pop(), number.pop(), number.pop());
number.push(holder);
}
ans = number.pop();
return ans;
} // end of evalExp
// checks to see which operand has a higher precedence if any
public static boolean hasPrecedence(char op1, char op2) {
if (op2 == '(' || op2 == ')')
return false;
if ((op1 == '*' || op1 == '/') && (op2 == '+' || op2 == '-'))
return false;
else
return true;
} // end hasPrecedence
// return result of operator and operands
public static int applyOp(char op, int b, int a) {
int ans = 0;
switch (op) {
case '+': ans = (a + b);
// return ans;
break;
case '-': ans = (a - b);
// return ans;
break;
case '*': ans = (a * b);
// return ans;
break;
case '/': ans = (a / b);
if (b == 0)
throw new ArithmeticException("Cannot divide by zero");
// return ans;
break;
}
return ans;
} //end applyOp
} //end Class Evaluate
Debugging the same would have given you the answer.
while (i < tokens.length && tokens[i] >= '0' && tokens[i] <= '9')
{
num.append(tokens[i++]);
}
In this code when you do i++, you have incremented the value of i but did not handle the char over there which is an operator in your use case.
while (i < tokens.length && tokens[i] >= '0' && tokens[i] <= '9')
{
num.append(tokens[i++]);
}
if (i != tokens.length)
i--;
Reverting the increment of the index fixes this issue. This may not be right solution. Just wanted to show the impact of the incremented index.
I am trying to convert string into integers but when I try to print the result I cannnot get the right output.
package com.company;
public class Main {
public static void main(String[] args){
String str ="-123456";
int i = atoi(str);
System.out.println(i);
}
public static int atoi(String str){
if (str == null || str.length() < 1)
return 0;
str = str.trim();
char flag = '+';
int i = 0;
if (str.charAt(0) == '-'){
flag = '-';
i++;
} else if (str.charAt(0) == '+'){
i++;
}
double result = 0;
while (str.length() > 1 && str.charAt(i) >= '0' && str.charAt(i) <= '9'){
result = result * 10 + (str.charAt(i)-'0');
i++;
}
if (flag == '-'){
result = -result;
}
if (result > Integer.MAX_VALUE){
return Integer.MAX_VALUE;
}
if (result < Integer.MIN_VALUE){
return Integer.MIN_VALUE;
}
return (int) result;
}
}
This is the result after I run the code
Change to this: Note i < str.length() instead of str.length() > 1
Explanation: Your error was "index out of range" meaning you're trying to access a character that isn't in the range of the length of the straight and ins this case str.charAt(7), which doesn't exist, so you have to limit i to being less than length of the string.
while (i < str.length() && str.charAt(i) >= '0' && str.charAt(i) <= '9'){
result = result * 10 + (str.charAt(i)-'0');
i++;
}
I was wondering how I could use an if statement as if they were integers for strings?
/**
*
* #param token
* #return true if parameter is the String representation of an integer
* between 0 and 255 (including 0 and 255), false otherwise.
* Strings "0", "1", "2" .... "254", "255" are valid.
* Padded Strings (such as "00000000153") are also valid
*/
public static boolean isValidElement(String token) {
if (token=> 0 || token <=255)
return true;
return false;
}
This is what I currently have in mind at the moment but obviously it won't work for strings.
You could use Integer.parseInt(), but it allows a leading +, and that's not allowed according to your javadoc.
You can manually test for leading +, then use Integer.parseInt() like this:
public static boolean isValidElement(String token) {
if (token == null || token.isEmpty() || token.charAt(0) == '+')
return false;
try {
int num = Integer.parseInt(token);
return (num >= 0 && num <= 255);
} catch (#SuppressWarnings("unused") NumberFormatException e) {
return false;
}
}
For a high-performance solution that don't rely on parseInt() and exception handling, you can use this much longer implementation:
public static boolean isValidElement(String token) {
if (token == null || token.isEmpty())
return false;
// skip leading zeroes
int i = 0;
while (i < token.length() && token.charAt(i) == '0')
i++;
// validate remaining
char ch;
switch (token.length() - i) {
case 0:
return true; // Allow "0"
case 1:
ch = token.charAt(i);
return (ch >= '1' && ch <= '9'); // Allow "1" to "9"
case 2:
ch = token.charAt(i);
if (ch >= '1' && ch <= '9') {
ch = token.charAt(i + 1);
return (ch >= '0' && ch <= '9'); // Allow "10" to "99"
}
return false;
case 3:
ch = token.charAt(i);
if (ch == '1') {
ch = token.charAt(i + 1);
if (ch >= '0' && ch <= '9') {
ch = token.charAt(i + 2);
return (ch >= '0' && ch <= '9'); // Allow "100" to "199"
}
} else if (ch == '2') {
ch = token.charAt(i + 1);
if (ch >= '0' && ch <= '4') {
ch = token.charAt(i + 2);
return (ch >= '0' && ch <= '9'); // Allow "200" to "249"
} else if (ch == '5') {
ch = token.charAt(i + 2);
return (ch >= '0' && ch <= '5'); // Allow "250" to "255"
}
}
return false;
default:
return false;
}
}
Try this:
if (Integer.parseInt(token) >= 0 || Integer.parseInt(token) <= 255) {
System.out.println(true);
}
This will cast the String token using the Integer wrapper class.
Use Integer.parseInt(yourString) for parsing an integer from String. You could try this:
public static boolean isValidElement(String token) {
try {
Integer n = Integer.parseInt(token);
return (n >= 0 && n <= 255);
} catch (NumberFormatException nfe) {
return false;
}
}
I'm having trouble with this codingbat exercise:
Returns true if for every * (star) in the string, if there are chars both immediately before and after the star, they are the same.
sameStarChar("xyyzz") // true
sameStarChar("xyzzz") // false
sameStarChar("xaaz") // true
The right answer is:
public boolean sameStarChar(String str) {
for (int i = 1; i < str.length() - 1; i++) {
if (str.charAt(i) == '*' && str.charAt(i - 1) != str.charAt(i + 1)) {
return false;
}
}
return true;
}
What I wrote is:
public boolean sameStarChar(String str) {
for (int i = 1; i < str.length() - 1; i++) {
if (str.substring(i, i + 1) == "*" && str.substring(i - 1, i) != str.substring(i + 1, i + 2)) {
return false;
}
}
return true;
}
I'm having trouble understanding the substring and charAt methods.
Instructions:
Returns true if for every '*' (star) in the string, if there are chars both immediately before and after the star, they are the same.
sameStarChar("xy*yzz") → true
sameStarChar("xy*zzz") → false
sameStarChar("*xa*az") → true
Pseudocode:
Loop over every character from 1 to length-1. If the character is an asterisk and the character before it is different from the one after, return false. Otherwise if when you reach the end, return true.
Code:
public boolean sameStarChar(String str){
int len = str.length();
for(int x = 1; x < len-1; x++){
if (str.charAt(x) == '*' && str.charAt(x-1) != str.charAt(x+1)){
return false;
}
}
return true;
}
Comments:
It's a linear time O(n) operation.
str.charAt() is easier to read and understand in this case.
Also, your substring solution should be more like
if (str.substring(i, i + 1).equals("*") &&
!str.substring(i - 1, i).equals(str.substring(i + 1, i + 2))){
//etc.
}
Substring returns a string, and to compare the literal sting value you have to use the .equals() method.
Instead, I count the number of '*' and number of pairs that are matched and check if they both are equal and return true.
public boolean sameStarChar(String str) {
int count=0, noOfPairs=0;
for(int i=1; i<str.length()-1;i++){
if(str.charAt(i)=='*') count++;
if(str.charAt(i)=='*' && str.charAt(i+1)==str.charAt(i-1)) noOfPairs++;
}
if(count==noOfPairs) return true;
return false;
}
Another solution to look at...
public boolean sameStarChar(String str) {
if(str.length()==0) return true;
if(str.length()==1 && str.contains("*")) return true;
if(!str.contains("*")) return true;
int i = 0;
boolean result = false;
while(i<str.length()-1){
if(i!=0 && str.charAt(i) == '*' && str.charAt(i-1) == str.charAt(i+1)){
result = true;
}else if(i!=0 && str.charAt(i) == '*' && str.charAt(i-1) != str.charAt(i+1)){
result = false;
}else if(str.charAt(i) == '*'){
result = true;
}
i++;
}
return result;
}
A version which does not iterate over each individual character in the string by using indexOf(int ch, int fromIndex)
public boolean sameStarChar(String str) {
int i=0;
int l=str.length();
for(i=str.indexOf("*",i);i!=-1;i=str.indexOf("*",i+1))
{
if(i==0 || i==l-1) //saves the program from accessing an out of bounds Index
continue;
else
{
if(str.charAt(i-1)!=str.charAt(i+1));
return false;
}
}
return true;
}