Calculator Class error checking - java

I'm doing some error checking for my BigInteger Calculator class. If an input has a space in between numbers and no valid operator (+,-,*,/,%,^) in between those numbers like the one below it is supposed to return "Error". Is there any way to check for this case using string methods?
Should return error because there is space in between numbers and no operator in between them:
2 + 1 1 1 1 1 + 2 //in this case the 1's do not have operators in between
2 2 2 //has spaces in between
valid:
2 + 2
22 + 2 + 1
2 + 11111 + 2

One option would be to split the string using String[] temp = [stringName].split(" "); and check to see that every other index is a valid operator.

Perhaps you can use regex to find space in between numbers.
String input = "1+2 2 2";
boolean found = Pattern.compile("[0-9]+\\s+[0-9]+").matcher(input).find();

You don't need to find the space between numbers specifically. In fact you should be ignoring spaces completely other than as delimiting the tokens.
You just need to scan and parse according to a grammar that doesn't have a syntax for two consecutive numbers. Or operators. At any given point you should know what's expected and what isn't.

Related

Hashmap in for loop not reading all the input

This is for AOC day 2. The input is something along the lines of
"6-7 z: dqzzzjbzz
13-16 j: jjjvjmjjkjjjjjjj
5-6 m: mmbmmlvmbmmgmmf
2-4 k: pkkl
16-17 k: kkkkkkkkkkkkkkkqf
10-16 s: mqpscpsszscsssrs
..."
It's formatted like 'min-max letter: password' and seperated by line. I'm supposed to find how many passwords meet the minimum and maximum requirements. I put all that prompt into a string variable and used Pattern.quote("\n") to seperate the lines into a string array. This worked fine. Then, I replaced all the letters except for the numbers and '-' by making a pattern Pattern.compile("[^0-9]|-"); and running that for every index in the array and using .trim() to cut off the whitespace at the end and start of each string. This is all working fine, I'm getting the desired output like 6 7 and 13 16.
However, now I want to try and split this string into two. This is my code:
HashMap<Integer,Integer> numbers = new HashMap<Integer,Integer>();
for(int i = 0; i < inputArray.length; i++){
String [] xArray = x[i].split(Pattern.quote(" "));
int z = Integer.valueOf(xArray[0]);
int y = Integer.valueOf(xArray[1]);
System.out.println(z);
System.out.println(y);
numbers.put(z, y);
}
System.out.println(numbers);
So, first making a hasmap which will store <min, max> values. Then, the for loop (which runs 1000 times) splits every index of the 6 7 and 13 16 string into two, determined by the " ". The System.out.println(z); and System.out.println(y); are working as intended.
6
7
13
16
...
This output goes on to give me 2000 integers seperated by a line each time. That's exactly what I want. However, the System.out.println(numbers); is outputting:
{1=3, 2=10, 3=4, 4=7, 5=6, 6=9, 7=12, 8=11, 9=10, 10=18, 11=16, 12=13, 13=18, 14=16, 15=18, 16=18, 17=18, 18=19, 19=20}
I have no idea where to even start with debugging this. I made a test file with an array that is formatted like "even, odd" integers all the way up to 100. Using this exact same code (I did change the variable names), I'm getting a better output. It's not exactly desired since it starts at 350=351 and then goes to like 11=15 and continues in a non-chronological order but at least it contains all the 100 keys and values.
Also, completely unrelated question but is my formatting of the for loop fine? The extra space at the beginning and the end of the code?
Edit: I want my expected output to be something like {6=7, 13=16, 5=6, 2=4, 16=17...}. Basically, the hashmap would have the minimum and maximum as the key and value and it'd be in chronological order.
The problem with your code is that you're trying to put in a nail with a saw. A hashmap is not the right tool to achieve what you want, since
Keys are unique. If you try to input the same key multiple times, the first input will be overwritten
The order of items in a HashMap is undefined.
A hashmap expresses a key-value-relationship, which does not exist in this context
A better datastructure to save your Passwords would probably just be a ArrayList<IntegerPair> where you would have to define IntegerPair yourself, since java doesn't have the notion of a type combining two other types.
I think you are complicating the task unnecessarily. I would proceed as follows:
split the input using the line separator
for each line remove : and split using the spaces to get an array with length 3
build from the array in step two
3.1. the min/max char count from array[0]
3.2 charachter classes for the letter and its negation
3.3 remove from the password all letters that do not correspond to the given one and check if the length of the password is in range.
Something like:
public static void main(String[] args){
String input = "6-7 z: dqzzzjbzz\n" +
"13-16 j: jjjvjmjjkjjjjjjj\n" +
"5-6 m: mmbmmlvmbmmgmmf\n" +
"2-4 k: pkkl\n" +
"16-17 k: kkkkkkkkkkkkkkkqf\n" +
"10-16 s: mqpscpsszscsssrs\n";
int count = 0;
for(String line : input.split("\n")){
String[] temp = line.replace(":", "").split(" "); //[6-7, z, dqzzzjbzz]
String minMax = "{" + (temp[0].replace('-', ',')) + "}"; //{6,7}
String letter = "[" + temp[1] + "]"; //[z]
String letterNegate = "[^" + temp[1] + "]"; //[^z]
if(temp[2].replaceAll(letterNegate, "").matches(letter + minMax)){
count++;
}
}
System.out.println(count + "passwords are valid");
}

Having trouble with using Hashmaps in java

In a program, I have to read in three lines of text. Each line has one space, with two objects on either side. The first is a string (an operator) and the second is a number (number). After reading in this 3 lines, I then put them into a hashmap to be later used.
I had a automatic method of adding the lines but for the purpose of trying to debug this problem I had to add the lines info manually into the map. Here is my current code:
String line1 = in.nextLine();
String line2 = in.nextLine();
String line3 = in.nextLine();
System.out.println(line1 + " " + line2 + " " + line3);
map.put(line1.split(" ")[0],
Integer.parseInt(line1.split(" ")[1]));
map.put(line2.split(" ")[0],
Integer.parseInt(line2.split(" ")[1]));
map.put(line3.split(" ")[0],
Integer.parseInt(line3.split(" ")[1]));
if (in.hasNextLine())
in.nextLine();
System.out.println("Size: " + map.size());
The first print statement (line1 + line2 + line3) prints the correct reading input that the map should have, each time:
* 4 - 3 / 2
It's then put into the map, then have calculations done, then printed out some true/false statements (in context with the program
* 4 - 3 / 2
Size: 3
- 3
Found solution for - 3. It's 1 4
/ 2
Found solution for / 2. It's 2 5
* 4
Not Possible.
As you can see, my program correctly goes through the map and has 3 entries (- 3, / 2, and * 4)
Now back to the top, where we want three more lines. Again here is the out statement of the three lines:
+ 5 + 6 - 2
Size: 2
- 2
Found solution for - 2. It's 1 3
+ 6
Found solution for + 6. It's 2 4
Not Possible.
What?? Same code - Read in 3 lines, RECOGNIZED 3 lines, but the first map.put did not actually put in the objects to the map. To put this into more perspective, the program goes like this:
3 lines are read in (format: 'operator number')
You are to use the numbers 1-6 and the operator given to make the number. BUT, you can only use each number (1-6) once in the 3 equations. The first one is fine:
* 4 - 3 / 2
Size: 3
- 3
Found solution for - 3. It's 1 4
/ 2
Found solution for / 2. It's 2 5
* 4
Not Possible.
For the first I have to use subtraction to get three. 4 - 1 is 3 so that's a pair. Now I need to use division to get 2, but I can't use 1 and 4. 6 / 3 = 2 so 6 and 3 are a pair. You get it.
here's my current code: Sorry for the sloppiness...
Thanks for any help...
KenKen.dat file
The next three lines are
+ 5
+ 6
- 2
and you use the operator as the key for the map entry. The javadocs of the Map interface states about duplicate key
An object that maps keys to values. A map cannot contain duplicate keys; each key can map to at most one value.
So first you put 5 whith the key +, then comes 6 with as key + too, here the first mapping is overridden. your map contains at the end of this reading step only two entries {+, 6} and {-, 2} hence the size of 2.
I doubt HashMap is the data structure you may want to use in this case. Instead create a class KenKenPair where you store each operand and operator found in a line
class KenKenPair {
final String operator;
final String operand;
public KenKenPair(String operator, String operand) {
this.operator = operator;
this.operand = operand;
}
public String getOperator() { return operator; }
public String getOperand() { return operand; }
}
and use
List<KenKenPair> list = new ArrayList<>();
to collect them all, then iterate over the List instead of the entry set.
Besides of that, be careful about your choices for the collections you want to use, for example entries in a WeakHashMap may be removed without you doing so explicitly.
The behavior of the WeakHashMap class depends in part upon the actions of the garbage collector, so several familiar (though not required) Map invariants do not hold for this class. Because the garbage collector may discard keys at any time, a WeakHashMap may behave as though an unknown thread is silently removing entries. In particular, even if you synchronize on a WeakHashMap instance and invoke none of its mutator methods, it is possible for the size method to return smaller values over time, for the isEmpty method to return false and then true, for the containsKey method to return true and later false for a given key, for the get method to return a value for a given key but later return null, for the put method to return null and the remove method to return false for a key that previously appeared to be in the map, and for successive examinations of the key set, the value collection, and the entry set to yield successively smaller numbers of elements.
Also there is no need to split the same line multiple times, instead split onces and assign the result to a local variable:
String parts[] = line1.split(" ");
list.add(new KenKenPair(parts[0], parts[1]));

Get Each Character From Output - Java

Right now I have a program that puts an inputted expression into Postfix Evaluation. Below is a copy of my console.
Enter an expression: ((5*2-1)/6+14/3)*(2*3-5)+7/2
5 2 * 1 - 6 / 14 3 / + 2 3 * 5 - * 7 2 / +
I now need to walk through the output, however this output is just a bunch of System.out.print 's put together. I tried using a stringBuilder however it cant tell the difference between 14 and a 1 and 4.
Is there anyway I can go through each character of this output? I need to put these numbers into a stack.
You can use String.split() and if you need only numbers regular expression.
Here is an Example:
public class Test {
public static void main(String[] args) {
String str = "1 * 2 3 / 4 5 6";
String[] arr = str.split(" ", str.length());
for (int i=0;i < arr.length;i++)
System.out.println(arr[i] + "is diggit? " + arr[i].matches("-?\\d+(\\.\\d+)?"));
}
}
str holds the long String. arr will hold the split sub strings.
you just need to make sure that each sub string differ one space from the other.
Well, you deleted your code while I was reading it, but here's a conceptually developed answer.
As you input every character, you want to push that to the stack.
The unique scenario you've mentioned 14 is unique in that it's two characters.
So what you would want to do is track if the last character was ALSO a number.
Here's a rough pseudo. Your stack should be all Strings to support this.
//unique case for digit
if(s.charAt(0).isDigit()) {
//check to see if the String at the top of a stack is a number by peeking at its first character
if(stack.peek().charAt(0).isDigit()) {
int i = Integer.parseInt(stack.pop()) * 10;
//we want to increment the entire String by 10, so a 1 -> 10
i = i + Character.getNumericValue(s.charAt(0)); //add the last digit, so 10 + 4 = 14
stack.push(Integer.toString(i)); //put the thing back on the stack
}
else {
//handle normally
stack.push(s.substring(0,1));
}
}
Is there a reason you need to parse the actual string?
If so, then what you do is, create a StringBuffer or StringBuilder, and wherever you put System.out.print in your code, append the buffer - including the spaces, which are what will help you differentiate between 1 4 and 14. Then you can convert that to a String. Then you can parse the String by splitting it by the spaces. Then iterate through the resulting String array.
If there is no reason for you to use the actual full string, you can instead use a List object and just add to it in the same places in the code. In this case, you don't need the spaces. Then you'll be able to simply iterate through the list.
You'll still be able to print you output - by printing the elements in the list.

How do I add order of operations to an expression solver?

Alright, so I'm trying to make an expression-as-a-string solver, so that the user can input a string, such as 2+4*5/10, and it will print out the answer, 4. I have some code written, but it doesn't apply the order of operations; it simply solves the equation in order of the operators - e.g. 2+4*5/10 would produce 3, which is incorrect. How do I make it so that multiplication and division are performed first, then addition and subtraction?
Here's the code I have right now:
class Expressions
{
String E;
void SetE(String e)
{
E = e;
}
int EvalE()
{
int res = 0;
int temp = 0;
char op = '+';
for(int i=0;i<E.length();i++)
{
if(E.charAt(i)=='*'||E.charAt(i)=='/'||E.charAt(i)=='+'||E.charAt(i)=='-')
{
if(op=='*')res*=temp;
else if(op=='/')res/=temp;
else if(op=='+')res+=temp;
else res-=temp;
temp=0;
op=E.charAt(i);
}
else
{
temp = temp*10+E.charAt(i)-'0';
}
}
if(op=='*')res*=temp;
else if(op=='/')res/=temp;
else if(op=='+')res+=temp;
else res-=temp;
return res;
}
}
Split the expression into two simpler expressions, then use recursion.
You have to do the following steps in precisely this order, or you will mess up the order of operations.
Look for the rightmost + sign. If there is such a +, then use recursion to evaluate the sub-expression to the left of it, then the sub-expression to the right of it, then add them and return the result.
If there's no + sign, then look for the rightmost - sign that's preceded by a number (that is, it's subtraction, not negation). If there is such a -, then use recursion to evaluate the sub-expression to the left of it, then the sub-expression to the right of it, then subtract them and return the result.
If there's no + or - sign, then look for the rightmost * sign. If there is such a *, then use recursion to evaluate the sub-expression to the left of it, then the sub-expression to the right of it, then multiply them and return the result.
If there's no +, - or * sign, then look for the rightmost * sign. If there is such a *, then use recursion to evaluate the sub-expression to the left of it, then the sub-expression to the right of it, then divide them and return the result. If you're using integers, you'll have to think about whether you want integer division or floating point. You might also want to do some kind of check around dividing by zero.
If there's no +, -, * or /, then all you've got is numbers and whitespace. Maybe a negative sign. Strip out the whitespace, parse it and return it.
Example: "6 - 5 - 4 + 3 * -2"
First, split at the +, and use recursion to evaluate "6 - 5 - 4 " and
" 3 * -2".
For "6 - 5 - 4 ", split at the second - , and use
recursion to evaluate "6 - 5 " and " 4 ".
For "6 - 5 ", split at the -, and use recursion to evaluate "6 " and " 5 ".
For " 3 * -2", split at the *, because the - is not preceded by a number. Use recursion to evaluate " 3 " and " -2 ".
For each of "6 ", " 5 ", " 4 ", " 3 " and " -2 ", there are no operators, so we just strip out the white space and parse.
The result of our calculation will be "((6-5)-4)+(3*-2)", so the order of operations worked out correctly.
Use two for loops.
In your first loop, search for * and / operators. Evaluate that part and replace that part of the string with the result of the evaluation.
In your second loop, do all the + and - as you're already doing.
So for the example you use, 2+4*5/10, your first loop would look for * or /. Upon finding the *, it evaluates 4*5. That's 20, so the string is modified into 2+20/10. Check again, and it finds the /, and modifies the string into 2+2.
Now you go through your second loop, and get 4.
You need to do two steps instead of one. In first step you parse equation into the reverse polish notation, then in second step you run through that and calculate results. Nice bonus is you get brackets support for (almost) free :-)

String addition with int

System.out.println(1+2+"3");
System.out.println("1"+2+3);
output:-
33
123
First case is understood but the second case is not clear.
If we are doing + operation in string then is works as append(concatenation).
So in your first case 1+2+"3" ... 1+2 =3 but when it perform 3+"3" java concate 3 into String 3 that is 33.
and in second example "1"+2+3 ... 2 is append into String "1" that results as 12 and then "12" + 3 so result is = 123.
if the left part is String then it would invoke + operation on string which is append(concatenation) , while in number it is summation
+ is right associative; "1"+2 results in "12", and adding 3 gives "123".
The evaluation happens left to right. First time a string is met all the succeeding values are implicitly cast to string before being added to the expression. So in the first case you have 1+2 = 3, then a string is met and 2 is appended to the string "3". Second case - the string "1" is met and then each int is cast to string before being added to the result accumulated so far.
If you add anything to a string, it will be a string so 1 + "2"(string) is "12"(string).
if you keep on adding to string, you will keep on getting strings "12"(string) + 33 is "1233"(string).
I think this better justify your question.
Thanks
Kapil Garg
well, mathematical expressions are scanned from right usually.
In first case, if you scan from right , u get two int operands(1 and 2) and u add it and it comes to be 3 as int when move on further you find one operand("3") is string so you concatenate it and it comes out to be 33.
In second case, if you scan from right u get one string operand("1") and you concatenate it with 2 so it comes out to be 12 as string, when you move on you find int(2), but this time your first operand(12) is string, so again you concatenate it and it comes out to be 123.
in first case 1+2+"3"
first 1+2 is added and appended with string so output is 33.
but in the second case: "1"+2+3
first string is appended with 2 so operation of "1"+2 is string, automatically last is ("12"+3) also string.
that is :
1st case:
numeric output + string = string
2nd case:
string + numeric = string
that is casting to parent class with lower/wrapper data types the final output would be parent class.

Categories