Detecting operator and operand errors in expression string - java

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
}

Related

Checking whether an expression is a valid formula

Recursion Question: A formula is defined as a string
containing positive single digits numbers, variables, and operations
(such that: +,-,/,*,%). In addition, the string doesn't contain space
bars. Each operation between two numbers or variables is separated
with brackets - "()".
Valid formulas would be: ((6+x)*(4+2)), (((9*4)+(x+8))*(6-5)), 6,
(3+1), etc...
Invalid formulas would be: -6, (1+*(x+2)*(1-6)), ( (6+x)), 10,
2+x, (33+3), ((1+2)), etc...
Write a boolean recursion function which gets a string - "s" and
returns true if he is a valid formula, and false otherwise.
The code has to be written via java.
My attempt: I have tried the following, putting in mind that the number of "(" is less equal to the number of ")", however, it doesn't right since: "((1+2))" isn't a valid formula. So I have written the following:
public static boolean isFormula(String s) {
return calc(s, 0, 0, 0, 0);
}
public static boolean calc(String s, int oc, int l, int r, int g) {
if (s == "") {
return (oc <= 1 && (l == r));
}
char c = s.charAt(0);
char e = s.charAt(s.length() - 1);
if (g == 0) {
if (!(op(s))) return false;
else {
return calc(s, oc, l, r, g + 1);
}
}
if (c == '(') {
return calc(s.substring(1), oc, l + 1, r, g);
} else if (c == ')') {
return calc(s.substring(1), oc, l, r + 1, g);
} else if ((c >= '0' && c <= '9') || c == 'x') {
if (oc <= 1) {
return calc(s.substring(1), 0, l, r, g);
}
} else if ((c == '+' || c == '-' || c == '*' || c == '/')) {
return calc(s.substring(1), oc + 1, l, r, g);
}
return false;
}
public static boolean op(String s) {
int count = 0;
if (s.charAt(0) == '+' || s.charAt(0) == '-' || s.charAt(0) == '*' || s.charAt(0) == '/') {
count++;
}
String d = s.replace("(", "");
if (d.charAt(0) == '+' || d.charAt(0) == '-' || d.charAt(0) == '*' || d.charAt(0) == '/') {
count++;
}
d = d.replace(")", "");
d = d.replace("+", ",");
d = d.replace("-", ",");
d = d.replace("*", ",");
d = d.replace("/", ",");
String[] words = d.split(",");
int sum = words.length;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == '+' || s.charAt(i) == '-' || s.charAt(i) == '/' || s.charAt(i) == '*') {
count++;
}
}
if (s.contains(" ")) return false;
return (count <= sum - 1);
}
Thoughts:
I find this question very complex, and I don't know how to arrange the code, because it doesn't seem that my way is correct and and it is so messy. I will be glad for some help. I put a lot of effort into writing this post. Thank you!
Try this.
static final Pattern DIGIT_OR_X = Pattern.compile("[\\dx]");
static final Pattern OPERATION = Pattern.compile("\\([\\dx][+*/%-][\\dx]\\)");
public static boolean isFormula(String s) {
while (true) {
if (DIGIT_OR_X.matcher(s).matches())
return true;
String rep = OPERATION.matcher(s).replaceAll("x");
if (rep.equals(s))
return false;
s = rep;
}
}
Test cases:
assertTrue(isFormula("((6+x)*(4+2))"));
assertTrue(isFormula("(((9*4)+(x+8))*(6-5))"));
assertTrue(isFormula("6"));
assertTrue(isFormula("(3+1)"));
assertFalse(isFormula("-6"));
assertFalse(isFormula("(1+*(x+2)*(1-6))"));
assertFalse(isFormula("( (6+x))"));
assertFalse(isFormula("10"));
assertFalse(isFormula("2+x"));
assertFalse(isFormula("(33+3)"));
assertFalse(isFormula("((1+2))"));
Or you can also do it without regular expression.
static boolean isFormula(String s) {
return new Object() {
int index = 0;
boolean match(String expects) {
if (index >= s.length() || expects.indexOf(s.charAt(index)) < 0)
return false;
++index;
return true;
}
boolean formula() {
if (match("0123456789x"))
return true;
return match("(")
&& formula() && match("+-*/%") && formula()
&& match(")");
}
boolean parse() {
return formula() && index >= s.length();
}
}.parse();
}

Evaluating infix expressions of unsigned integers using 2 stacks and getting wrong answer

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 integer, but I cannot print the result out

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++;
}

How do I compare strings representation of integers?

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;
}
}

Recursive expression evaluation?

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.

Categories

Resources