I have a method that checks to see if an equation written is correct.
This method check for:
Multiple Parentheses
Excess operators
Double Digits
q's
and any character in a string that is not and of these:
.
private static final String operators = "-+/*%_";
private static final String operands = "0123456789x";
It was working fine, but then I added in modular to the operators and now whenever my code reaches the part in the method that checks to the left and the right of an operand to see if it is neither the end of the string or the beginning I get an error saying
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 3
My method and all it's additional methods.
private static final String operators = "-+/*%_";
private static final String operands = "0123456789x";
public Boolean errorChecker(String infixExpr)
{
char[] chars = infixExpr.toCharArray();
StringBuilder out = new StringBuilder();
for (int i = 0; i<chars.length; i++)
{
System.out.print(infixExpr.charAt(i));
if (isOperator(infixExpr.charAt(i)))
{
if (i == 0 || i == infixExpr.length())
{
out.append(infixExpr.charAt(i));
}
else if (isOperator(infixExpr.charAt(i + 1)) && isOperator(infixExpr.charAt(i - 1)))
{
System.out.println("To many Operators.");
return false;
}
else if (isOperator(infixExpr.charAt(i + 1)))
{
if (infixExpr.charAt(i) != '-' || infixExpr.charAt(i + 1) != '-')
{
System.out.println("To many Operators.");
return false;
}
}
else if (isOperator(infixExpr.charAt(i - 1)))
{
if (infixExpr.charAt(i) != '-' || infixExpr.charAt(i - 1) != '-')
{
System.out.println("To many Operators.");
return false;
}
}
}
else if (isOperand(infixExpr.charAt(i)))
{
if (i == 0 || i == infixExpr.length())
{
out.append(infixExpr.charAt(i));
}//THE LINE RIGHT BELOW THIS COMMENT THROWS THE ERROR!!!!!
else if (isOperand(infixExpr.charAt(i + 1)) || isOperand(infixExpr.charAt(i - 1)))
{
System.out.println("Double digits and Postfix form are not accepted.");
return false;
}
}
else if (infixExpr.charAt(i) == 'q')
{
System.out.println("Your meow is now false. Good-bye.");
System.exit(1);
}
else if(infixExpr.charAt(i) == '(' || infixExpr.charAt(i) == ')')
{
int p1 = 0;
int p2 = 0;
for (int p = 0; p<chars.length; p++)
{
if(infixExpr.charAt(p) == '(')
{
p1++;
}
if(infixExpr.charAt(p) == ')')
{
p2++;
}
}
if(p1 != p2)
{
System.out.println("To many parentheses.");
return false;
}
}
else
{
System.out.println("You have entered an invalid character.");
return false;
}
out.append(infixExpr.charAt(i));
}
return true;
}
private boolean isOperator(char val)
{
return operators.indexOf(val) >= 0;
}
private boolean isOperand(char val)
{
return operands.indexOf(val) >= 0;
}
My main portion that runs the method:
Boolean meow = true;
while(meow)
{
System.out.print("Enter infix expression: ");
infixExpr = scan.next();//THE LINE RIGHT BELOW THIS COMMENT THROWS THE ERROR!!!!!
if(makePostfix.errorChecker(infixExpr) == true)
{
System.out.println("Converted expressions: "
+ makePostfix.convert2Postfix(infixExpr));
meow = false;
}
}
It was working fine before, but now it won't even pass 1+2 which was previously working and I changed NONE of that you see. What's wrong!?!?
What looks like what's happening is that you check for the character at index (i + 1) several times in your code. Lets say you input a string with a length of five characters. The program goes through and reaches the line:
else if (isOperator(infixExpr.charAt(i + 1)) && isOperator(infixExpr.charAt(i - 1)))
If i == 4, this will cause the code:
infixExpr.charAt(i + 1)
to throw an index error.
In essance, you're checking for a character at index five (the sixth character) in a string with a maximum index index of four which is five characters in length. Also, your checking for
if(i==0 || i == infixExpr.length)
won't work as is. Maybe check for (i==infixExpr.length-1).
Related
I have no idea how to check if char[] contains only one letter (a or b) on the first position and only one int (0-8) on the second position. for example a2, b2
I have some this, but I do not know, what should be instead of digital +=1;
private boolean isStringValidFormat(String s) {
boolean ret = false;
if (s == null) return false;
int digitCounter = 0;
char first = s.charAt(0);
char second = s.charAt(1);
if (first == 'a' || first == 'b') {
if (second >= 0 && second <= '8') {
digitCounter +=1;
}
}
ret = digitCounter == 2; //only two position
return ret;
}
` public char[] readFormat() {
char[] ret = null;
while (ret == null) {
String s = this.readString();
if (isStringValidFormat(s)) {
ret = s.toCharArray();
}else {
System.out.println("Incorrect. Values must be between 'a0 - a8' and 'b0 - b8'");
}
}
return new char[0];
}`
First, I would test for null and that there are two characters in the String. Then you can use a simple boolean check to test if first is a or b and the second is between 0 and 8 inclusive. Like,
private boolean isStringValidFormat(String s) {
if (s == null || s.length() != 2) {
return false;
}
char first = s.charAt(0);
char second = s.charAt(1);
return (first == 'a' || first == 'b') && (second >= '0' && second <= '8');
}
For a well understood pattern, use Regex:
private static final Pattern pattern = Pattern.compile("^[ab][0-8]$")
public boolean isStringValidFormat(String input) {
if (input != null) {
return pattern.matcher(input).matches();
}
return false;
}
I have a string "{x{y}{a{b{c}{d}}}}"
And want to print out recursively.
x
-y
-a
--b
---c
---d
This is what I have so far -
private static void printPathInChild2(String path) {
if (path.length() == 0) {
return;
}
if (path.charAt(0) == '{') {
for (int i = 0; i < path.length(); i++) {
if (path.charAt(i) == '{' && i != 0) {
String t1 = path.substring(0,i);
System.out.println(t1);
printPathInChild2(path.substring(i));
} else if (path.charAt(i) == '}') {
String t2 = path.substring(0, i+1);
System.out.println(t2);
printPathInChild2(path.substring(i+1));
}
}
}
}
Struggling with the termination logic
If you want to add '-' characters that depend on the depth of the nesting, you should pass a second argument to the recursive call, which keeps track of the prefix of '-' characters.
When you encounter a '{', you add a '-' to the prefix.
When you encounter a '}', you remove a '-' from the prefix.
When you encounter any other character, you print the prefix followed by that character.
private static void printPathInChild2(String path,String prefix) {
if (path.length() == 0) {
return;
}
if (path.charAt(0) == '{') {
printPathInChild2(path.substring(1),prefix + "-");
} else if (path.charAt(0) == '}') {
printPathInChild2(path.substring(1),prefix.substring(0,prefix.length()-1));
} else {
System.out.println (prefix.substring(1) + path.charAt(0));
printPathInChild2(path.substring(1),prefix);
}
}
When you call this method with:
printPathInChild2("{x{y}{a{b{c}{d}}}}","");
You get:
x
-y
-a
--b
---c
---d
(I see that in your expected output 'd' has 4 '-'s, but I think it's an error, since 'd' has the same nesting level as 'c', so it should have 3 '-'s).
The method can also be written as follows:
private static void printPathInChild2(String path,String prefix) {
if (path.length() == 0) {
return;
}
char c = path.charAt(0);
if (c == '{') {
prefix = prefix + '-';
} else if (c == '}') {
prefix = prefix.substring(0,prefix.length()-1);
} else {
System.out.println (prefix.substring(1) + c);
}
printPathInChild2(path.substring(1),prefix);
}
I'm trying to solidify my understanding of stacks and operators by creating a simple calculator to process arithmetic expressions that involve parentheses. I feel like I have code that should work, but it's most certainly not giving me the right output.
Even though I have a method to evaluate each expression, when I try to return the number stack it does not print out any evaluated method but only all numbers inputted by the user. I want to deal with issues in input like mismatched operators or missing parentheses as well.
I attempt to run the code with simple expressions like 9 * 5 or something like (7 * 6) + (9 - 4) and it just returns the last double regardless.
Here's my code so far:
Main method
import java.util.Stack;
import javax.swing.JOptionPane;
public class Calculator {
// instance variables
private Stack < Double > nums;
private Stack < String > ops;
String list;
// constructor
public Calculator()
{
nums = new Stack < Double > ();
ops = new Stack < String > ();
}
// methods
public static boolean isDouble(String str) {
try {
Double.parseDouble(str);
} catch (NumberFormatException e) {
return false;
} catch (NullPointerException e) {
return false;
}
return true;
}
public static boolean isValidOp(String str) {
return (str == "(" || str == ")" || str == "^" || str == "*" || str == "/" || str == "+" || str == "-");
}
public int prec(String str) {
if (str == "(" || str == ")")
return 4;
if (str == "^")
return 3;
if (str == "*" || str == "/")
return 2;
if (str == "+" || str == "-")
return 1;
else
return -1;
}
public double applyOperator(double left, String op, double right) {
if (op == "+") {
return (left + right);
}
if (op == "-") {
return (left - right);
}
if (op == "*") {
return (left * right);
}
if (op == "/") {
return (left / right);
}
if (op == "^") {
return Math.pow(left, right);
} else {
throw new IllegalArgumentException("Not a valid operator");
}
}
public String evaluate(String str)
{
String [] tokens = str.split(" ");
for (int i = 0; i < tokens.length; i++)
{
if (isDouble(tokens [i]) == true)
{
nums.push(Double.parseDouble(tokens [i]));
}
if (tokens [i] == "(")
{
ops.push(tokens [i]);
}
if (tokens [i] == ")")
{
String op1 = ops.pop();
double num1 = nums.pop();
double num2 = nums.pop();
double result = applyOperator(num1,op1,num2);
nums.add(result);
}
if (tokens [i] == "+" || tokens [i] == "-" || tokens [i] == "*" || tokens [i] == "/" || tokens [i] == "^")
{
if(ops.isEmpty())
{
ops.push(tokens [i]);
}
else if (prec(tokens [i]) > prec(ops.peek()))
{
ops.push(tokens [i]);
}
else if (prec(tokens [i]) < prec(ops.peek()) && !ops.isEmpty() && ops.peek() != "(")
{
String ac1 = ops.pop();
double res1 = nums.pop();
double res2 = nums.pop();
double outcome = applyOperator(res1,ac1,res2);
nums.add(outcome);
}
}
}
while(!ops.isEmpty() && nums.size() > 1)
{
String ab = ops.pop();
double bb = nums.pop();
double cb = nums.pop();
double clac = applyOperator(bb,ab,cb);
nums.add(clac);
}
String fix = nums.pop().toString();
return fix;
}
}
Tester:
import javax.swing.JOptionPane;
public class AppforCalc {
public static void main(String [] args)
{
Calculator calc = new Calculator();
String reply = "yes";
String instructions = "Enter a mathematical expression. Separate everything with spaces";
while(reply.equalsIgnoreCase("yes"))
{
String expression = JOptionPane.showInputDialog(instructions);
String ans = calc.evaluate(expression);
reply = JOptionPane.showInputDialog("The solution is " + ans + "Try again?");
}
}
}
The main reason you algorithm fails is due to using == when trying to check for String equality.
In Java, == is a boolean operator which behaves identically for all operands, and checks the equality of the values of the operands. This means that primitives are checked as one might expect, but Strings, which are objects, will result in comparing the memory references of the two Strings, which will result in true only if the two Strings are actually the same String. This means that String equality checks must be done with the equals method.
There are more issues with the behavior of the calculator (algorithmic ones), but those will be easier to identify and fix after handling the String equality checks. One example of an issue that must be fixed is:
while(!ops.isEmpty() && nums.size() > 1)
{
String ab = ops.pop();
double bb = nums.pop();
double cb = nums.pop();
double clac = applyOperator(bb,ab,cb);
nums.add(clac);
}
The operands (bb and cb) are popped from a Stack, therefore they arrive in a reveresed order (when parsed, cb was pushed into the stack before bb). This means that cb is the leftside operand and bb is the rightside operand -> double clac = applyOperator(cb,ab,bb); The same refactoring should be done for all usages of the applyOperand method.
Another issue is the following:
else if (prec(tokens [i]) < prec(ops.peek()) && !ops.isEmpty() && ops.peek() != "(")
{
String ac1 = ops.pop();
double res1 = nums.pop();
double res2 = nums.pop();
double outcome = applyOperator(res1,ac1,res2);
nums.add(outcome);
}
An internal evaluation was made, but the triggering of the evaluation is the discvery of an operand with a lower presendence. The operand should be pushed into the operations stack after the evaluation:
else if (prec(tokens [i]) < prec(ops.peek()) && !ops.isEmpty() && ops.peek() != "(")
{
...
...
nums.add(outcome); // I highly suggest refactoring this to nums.push due to readability considerations
ops.push(tokens[i]);
}
References:
The difference between == and equals in Java
Guide for implementing a scientific calculator (in c++, use as an algorithmic reference)
The Shunting Yard Algorithm - As suggested by user207421
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)));
I have the following function.
private boolean codeContains(String name, String code) {
if (name == null || code == null) {
return false;
}
Pattern pattern = Pattern.compile("\\b" + Pattern.quote(name) + "\\b");
Matcher matcher = pattern.matcher(code);
return matcher.find();
}
It is called many thousand times in my code, and is the function in which my program spends the most amount of time in. Is there any way to make this function go faster, or is it already as fast as it can be?
If you don't need to check word boundaries, you might do this :
private boolean codeContains(String name, String code) {
return name != null && code != null && code.indexOf(name)>=0;
}
If you need to check word boundaries but, as I suppose is your case, you have a big code in which you often search, you could "compile" the code once by
splitting the code string using the split method
putting the tokens in a HashSet (checking if a token is in a hashset is reasonably fast).
Of course, if you have more than one code, it's easy to store them in a structure adapted to your program, for example in a map having as key the file name.
"Plain" string operations will (almost) always be faster than regex, especially when you can't pre-compile the pattern.
Something like this would be considerably faster (with large enough name and code strings), assuming Character.isLetterOrDigit(...) suits your needs:
private boolean codeContains(String name, String code) {
if (name == null || code == null || code.length() < name.length()) {
return false;
}
if (code.equals(name)) {
return true;
}
int index = code.indexOf(name);
int nameLength = name.length();
if (index < 0) {
return false;
}
if (index == 0) {
// found at the start
char after = code.charAt(index + nameLength);
return !Character.isLetterOrDigit(after);
}
else if (index + nameLength == code.length()) {
// found at the end
char before = code.charAt(index - 1);
return !Character.isLetterOrDigit(before);
}
else {
// somewhere inside
char before = code.charAt(index - 1);
char after = code.charAt(index + nameLength);
return !Character.isLetterOrDigit(after) && !Character.isLetterOrDigit(before);
}
}
And a small test succeeds:
#Test
public void testCodeContainsFaster() {
final String code = "FOO some MU code BAR";
org.junit.Assert.assertTrue(codeContains("FOO", code));
org.junit.Assert.assertTrue(codeContains("MU", code));
org.junit.Assert.assertTrue(codeContains("BAR", code));
org.junit.Assert.assertTrue(codeContains(code, code));
org.junit.Assert.assertFalse(codeContains("FO", code));
org.junit.Assert.assertFalse(codeContains("BA", code));
org.junit.Assert.assertFalse(codeContains(code + "!", code));
}
This code seemed to do it:
private boolean codeContains(String name, String code) {
if (name == null || code == null || name.length() == 0 || code.length() == 0) {
return false;
}
int nameLength = name.length();
int lastIndex = code.length() - nameLength;
if (lastIndex < 0) {
return false;
}
for (int curr = 0; curr < lastIndex; ) {
int index = code.indexOf(name, curr);
int indexEnd = index + nameLength;
if (index < 0 || lastIndex < index) {
break;
}
boolean leftOk = index == curr ||
index > curr && !Character.isAlphabetic(code.charAt(index - 1));
boolean rightOk = index == lastIndex ||
index < lastIndex && !Character.isAlphabetic(code.charAt(indexEnd));
if (leftOk && rightOk) {
return true;
}
curr += indexEnd;
}
return false;
}
The accepted answer goes to dystroy as he was the first to point me in the right direction, excellent answer by Bart Kiers though, +1!