Ok, I think I have something. Sorry for the late answer, I hope you can still use it.
First let me explain, I changed quite a lot of code.
scanning the input
the input will be read as one complete String, as in your code. But instead of splitting the code into a String[]
, I am 'checking' the chars one by one and try to decide whether they are an operator or a number.
If I find a number or an operator, I put it in an list instead of an array, because a list can grow dynamically and I don't know how many numbers and operators there are,yet.
private static ArrayList<String> getSequence(String input) {
String number = "[\\d,.]+"; // RegEx to detect any number 12 or 1.2 or 1,2
String function = "[+\\-*/]+"; // RegEx to detect any operator +-*/
char[] inputChars = input.toCharArray(); // converting the input String into an array
ArrayList<String> sequence = new ArrayList<>(); // this is the list, that will be returned
String lastNumber = ""; // a number can consist of multiple chars, so this String is like a buffer for us where we "collect" every char until the number is complete
for (char c : inputChars) { // now we loop through every char in the char[]
System.out.println("checking " + c);
if ((new String("" + c)).matches(function)) { // we convert our char into a String and try to match it with the "function" RegEx
System.out.println("its an operator");
if (!lastNumber.isEmpty()) {
sequence.add(lastNumber); // if we detect an operator, we must check if we still have a number in our buffer. So we add the last number to our list
}
sequence.add("" + c); // and we add our operator to our list
lastNumber = ""; // we just saw an operator, so the "lastNumber" buffer should be cleared
} else if ((new String("" + c)).matches(number)) { // if we detect a digit/number
System.out.println("its part of a number");
lastNumber += c; // since this char is part of a number, we add it to the "lastNumber" buffer
// now we need to continue, since we don't know if the number is already finished
}
}
// if we finished analyzing the char array, there might be a last number in our buffer
if (!lastNumber.isEmpty()) {
sequence.add(lastNumber); // the last number will be added too
}
return sequence; // now our sequence is complete and we return it
}
So when our input would be something like 1+2+3
this method would return this list:
{"1", "+", "2", "+", "3"}
evaluating the sequence
Next we call the method evaluate(sequence)
to evaluate our list. This is pretty close to your way, I just made some adjustments
private static void evaluate(ArrayList<String> sequence) {
double number1 = 0.0; // the first number is also a intermediary result
while (true) { // we actually don't know how long the equation is, so here we have an infinite-loop. Usually not a good idea!
try { // we try to evaluate the next String of our sequence
number1 = getNextNumber(sequence); // get the next number
System.out.println("number1 = " + number1);
char operator = getNextOperator(sequence); // get the next operator
System.out.println("operator = " + operator);
double number2 = getNextNumber(sequence);
System.out.println("number2 = " + number2); // get the second number
switch (operator) { // I replaced your if statements with that switch (but it is actually the same)
case '+':
number1 += number2; // we add the second number to the first number and "store" the result in the first number
break;
case '-':
number1 -= number2;
break;
case '*':
number1 *= number2;
break;
case '/':
number1 /= number2;
break;
}
} catch (java.lang.IndexOutOfBoundsException e) { // here we break out of the loop. We can be 100% sure that at some point we reached the end of the list. So when we are at the end of the list and try to access the "next" element of the list (which does of course not exist) we get that IndexOutOfBoundsException and we know, we are finished here
System.out.println("result is " + number1);
break; // break out of the loop
}
}
}
The important part here is actually that we store the result of any operation with two numbers, in the first number. So if we have 1+2+4
, it will first evaluate 1+2
, store the result as the first number and then evaluate 3+4
helper methods
Now we still need the methods to detect either an operator or a number;
private static char getNextOperator(ArrayList<String> sequence) {
String function = "[+\\-*/]+"; // the same regex as before to detect any operator
// with a list it looks like this
// list.get(0) is the same as array[0]
if (sequence.get(0).matches(function)) {
return sequence.remove(0).charAt(0);
}
return ' ';
}
This uses a nice trick here: sequence.get(0)
will have a look at the first element in the list and return its value. But sequence.remove(0)
will return its value and delete the element from the list at the same time. So the original first element will no longer be there and the previously second element becomes the first...
So first our list looks like { "-", "2"}
and after calling getNextOperator()
it looks like {"2"}
, because we remove the operator.
And the same we do for getting the next number:
private static double getNextNumber(ArrayList<String> sequence) {
String sign = "[+-]+"; // regex to test if a string is only a sign (+ or -)
String number = "[\\d,.]+"; //regex to test if a String is a number (with or without . or ,
double number1 = 0;
if (sequence.get(0).matches(sign) && sequence.get(1).matches(number)) {
// first one should be a sign and the second one a number
number1 = Double.parseDouble(sequence.remove(0) + sequence.remove(0));
} else if (sequence.get(0).matches(number)) {
// its a normal number
number1 = Double.parseDouble(sequence.remove(0));
}
return number1;
}
Well and that's it. Now you only have to put it all together and call it in your main function like this:
public static void main(String[] args) {
try (Scanner console = new Scanner(System.in)) {
String input;
System.out.print(">>> ");
input = console.nextLine();
ArrayList<String> sequence = getSequence(input); // analyze input and get a list
evaluate(sequence); // evaluate the list
System.out.println("The console is now closed.");
}
}
Well, sorry for changing so much. I couldn't think of another (maybe more efficient) way to do that. This calculator is not very "smart" for now and there are a lot of things it won't handle (like letters or braces) but I hope it's a start. At least it should work with negative and positive numbers now and it should be able to handle even longer equations.
cheers!