Printing out an Expression manipulated by a Stack JAVA - java

Hey guys so heres my question. I've got a class that manipulates a stack of Fractions and it is an RPN Evaluator. I'm newer to Java and only know basic data structures. This is a project for a class but I'm kinda bummed. I need to print out the expression that I used OR print out the expression until the RPN expression isn't valid denoted by valid = false/true I have a specific way I have to print it out and ill give an example but I cannot figure out how to do it... I have a queue available to me to use but I must use both a stack and a queue. I realize the code is yuck but its because I haven't begun my cleanup of that class yet. Here is an example of the output I need if the inputs are as follows.... Note that the input is in quotes minus the quotes
Input************************************Output
"(2/5)(1/2) * * #" *********** Expression 3 is: (2/5)(1/2)**
"(3/1)T ^ (3/2) #" *********** Expression 4 is: (3/1)T
Here is my class(I know it's sloppy...and the rules are very restrictive on what I can and can't use. No linked lists etc....)
import java.util.Scanner;
public class RpnEvaluator
{
private final int MAX_TOKEN = 20;
private Scanner stdin;
private int count = 0;
public void run() throws java.io.IOException
{
runOnce();
}
public boolean isOperator(String input)
{
String[] oprtr = {"+", "-", "*"};
for(String choice: oprtr)
if(choice.equals(input))
return true;
return false;
}
public boolean isOperation(String input)
{
if(input.startsWith("(", 0))
return true;
return false;
}
public Fraction runOperation(String choice, Fraction op2, Fraction op1)
{
Fraction newFract = new Fraction();
if(choice.equals("*"))
newFract = new Fraction(op1.times(op2));
else if(choice.equals("+"))
newFract = new Fraction(op1.plus(op2));
else if(choice.equals("-"))
newFract = new Fraction(op1.minus(op2));
return newFract;
}
public void runOnce()
{
String readIn = "";
boolean valid = true;
Fraction op1 = null, op2 = null, answer = null, myFract;
Queue myQueue = new Queue(MAX_TOKEN);
Stack myStack= new Stack(MAX_TOKEN);
stdin = new Scanner(System.in);
while(stdin.hasNext() && valid == true)
{
readIn = stdin.next();
if(readIn.equals("#"))
{
break;
}
else if(!isOperator(readIn) && isOperation(readIn))
{
myFract = new Fraction(readIn);
myStack.push(myFract);
}
else if(isOperator(readIn))
{
if(myStack.isEmpty())
valid = false;
else
op2 = (Fraction)myStack.pop();
if(myStack.isEmpty())
valid = false;
else
op1 = (Fraction)myStack.pop();
myStack.push(runOperation(readIn, op2, op1));
}
else
valid = false;
}
if(myStack.isEmpty())
valid = false;
else
answer = (Fraction)myStack.pop();
if(!myStack.isEmpty())
valid = false;
if(valid == false)
{
System.out.print("Expression " + ++count + ": ");
System.out.println("Invalid Expression");
}
else
{
System.out.println("Expression " + ++count + ": ");
System.out.println("The value is: " + answer.toString());
}
clear(myStack, myQueue);
}
public void clear(Stack myStack, Queue myQueue)
{
myStack.clear();
myQueue.clear();
}
}

I've got a class that manipulates a stack of Fractions and it is an RPN Evaluator.
No it isn't. It's an attempt, but it doesn't handle parentheses at all, or operator precedence. You need to look up the Dijsktra shunting-yard algorithm. If this is an assignment I have no doubt that this algorithm was mentioned in class, probably at great length.
I realize the code is yuck but its because I haven't begun my cleanup of that class yet.
The best way to cleanup a class is not to fill it with dirt in the first place. Writing code that has to be subsequently removed is a double waste of time.

Ok it is very unclear what you are asking and your code doesn't make too much sense and the fraction variable fraction is unknown.
and just a note here always clean up your code as write it since later you will never know where it is and will always be confusing.
try http://www.planet-source-code.com/vb/scripts/search.asp?lngWId=2.
for some examples, they always have what i need.
and if you are new to java and want to know more i would suggest the book Java Programming: From Problem Analysis to Program Design, it explains everything from main method to GUI design.
and in future please explain your problem in more detail, we have no idea what you are asking.
Thanks.

Related

Character.isDigit parameters and line unavailable errors within the isDigit method (clarification)

I'm currently working on a small project for an introductory java class. We're supposed to make a program which can take in an integer from the user and output the number of odds, evens, and zeroes present within the code. This seemed pretty easy to me, and I managed to implement the code, but a class mate, after I criticized his code for incorrectly following the prompt, noted that my code would crash if anything but digits was input.
Out of spite I've tried to go beyond the prompt and have the program output an error message if it encounters characters aside from digits (instead of having my compiler return an error). However I'm returning multiple errors within the Eclipse compiler when using the isDigit method in the Character class.
I don't know exactly what's causing this, and I feel I must be missing something crucial, but my teacher quite frankly isn't qualified enough to understand what's causing the error, and none of my classmates can seem to figure it out either.
package ppCH5;
import java.util.Scanner;
public class PP5_3
{
public static void main(String[]args)
{
int even = 0;
int odd = 0;
int zero = 0;
int num = 0;
int count = 0;
boolean inputError = false;
System.out.println("please provide some integer");
Scanner scan = new Scanner(System.in);
String numbers = scan.next();
scan.close();
Scanner intSeperate = new Scanner(numbers);
intSeperate.useDelimiter("");
while(intSeperate.hasNext())
{
if(Character.isDigit(numbers.charAt(count)))
{
count++;
num = intSeperate.nextInt();
if((num % 2)==1)
odd++;
if((num % 2)==0)
if(num==0)
zero++;
else
even++;
}
else
{
count++;
inputError = true;
}
}
intSeperate.close();
if(!inputError)
{
System.out.println("There are " + even + " even digits.\n" + odd + " odd digits.\nAnd there are " + zero + " zeros in that integer.");
}
else
{
System.out.println("You have provided a disallowed input");
}
}
}
Any help would be appreciated, I'm currently at a loss.
When you enter a single non-digit character, say a, the else branch inside the while loop will get executed, incrementing count, right? And then the loop will start a new iteration, right?
In this new iteration, intSeparator.hasNext() still returns true. Why? Because the input a is never read by the scanner (unlike if you have entered a digit, intSeparator.nextInt would be called and would have consumed the input).
Now count is 1 and is an invalid index for the 1-character string. Therefore, numbers.charAt(count) throws an exception.
This can be avoided if you break; out of the loop immediately in the else block:
else
{
inputError = true;
break;
}
Also, don't close the scan scanner. scan is connected to the System.in stream. You didn't open that stream, so don't close it yourself.

Empty check with parse int

A few days ago i posted a topic about if/else and while loops.
I have gotten a bit further and now made a little program to guess a number.
I would like to implement a feature to check if the user has an empty input but i cannot seem to figure it out!
Is there anyone who can help me a bit? Im still a pretty early beginner at JAVA.
Here is my current code:
import java.util.Scanner;
import javax.swing.JOptionPane;
/**
*
* #author henluu
*/
public class Practice {
public static void main(String[] args) {
//create new scanner
Scanner input = new Scanner(System.in);
int raad = 0;
raad = Integer.parseInt(JOptionPane.showInputDialog("Guess the number"));
while (Practice.rn() != raad) {
JOptionPane.showMessageDialog( null, ("Your number is not the same as the random number"));
raad = Integer.parseInt(JOptionPane.showInputDialog("Guess the number"));
//empty check
if (raad == " ") {
Integer.parseInt(JOptionPane.showInputDialog("No Input"));
}
}
JOptionPane.showMessageDialog( null, ("You guesse dit right! The number was: ") + Practice.rn());
}
//method to generate random number
public static int rn() {
int random = (int) Math.floor((Math.random() * 10) + 1);
return random;
}
}
The point is: that JOptionPane is returning a string to you.
You could do something like:
private int fetchIntFromString(String userInput) {
if (userInput.isEmpty()) {
throw new IllegalArgumentException("input must not be empty");
}
return Integer.parseInt(userInput);
}
to be used like:
try {
raad = fetchIntFromString(JOptionPane.show...
} catch (Exception e) {
... give some error message
In other words: when the user gives a number, it is simply turned into a numeric value and returned. If the user input is empty or can't be parsed as number, an exception is thrown; which needs to be caught within the method that calls fetchIntFromString()
Since you are learning i'm not going show you the standard library solutions, but a solution that is library independant and allows you to grasp some logic points to check.
See the comments in the code below.
public boolean isNumeric(String input) {
// First trim input of trailing spaces
input = input.trim();
// test on 0 length
if(input.length == 0) {
return false;
}
// Loop through all characters to test
// if they are valid
for(char c : input.toCharArray()) {
if (!Character.isDigit(c)) return false;
}
return true;
}
You can then call it like this.
if(this.isNumeric(raad)) {
// your code here
}
Further more, learn about the single responsiblity principle.
There are some serious flaws in your code. I'd suggest you post it also on code review to get some useful pointers where to learn.

Guessing Game Help :)

Ok, so my computer teacher has asked us to make a simple game that asks the user to guess a radomly generated number, but I want to take it one step further and make it so that it display error messages when the user tries certain things. The problem here is that I am new to booleans and well, I am having a bit of trouble using java.util.Scanner and booleans. So, if anyone could take a quick look at this I would appreciate it.
import java.util.Scanner;
import java.util.Random;
public class MoreGuessing{
//Instantiation
Scanner reader = new Scanner(System.in);
Random number = new Random();
//Variables
int randomnumber = number.nextInt(10) + 1;
int cntr = 1;
static String decimalguessed;
String error1 = "Error001: Decimal found, please enter a whole number between 1-10." + "\n" + "Program terminated......";//Decimal portion error.
String error2 = "Please enter a positive number." + "\n" + "Program terminated......"; //Negative number error.
String error3 = "Unknown character entered." + "\n" + "Program terminated......"; //Unknown character error.
//Verifier
public static boolean verifyLetters() {
if (decimalguessed.matches("[a-zA-Z]+")){
return true;
}else{
return false;
}
}
public static void main(String [] args){
//Input and display
System.out.print("Please enter a whole number between 1-10: ");
decimalguessed = reader.nextLine();
//Process and Errors
while (decimalguessed != randomnumber) {
if (verifyLetters() != false){
System.out.println(error3);
System.exit(1);}
if (decimalguessed % 1 != 0) {
System.out.println(error1);
System.exit(1);}
if (decimalguessed < 0) {
System.out.println(error2);
System.exit(1);}
if (randomnumber != decimalguessed){
System.out.println("You've lost, please make another attempt.");}
System.out.print("Please enter a whole number between 1-10: ");
decimalguessed = reader.nextDouble();
cntr++;
}
if (cntr == 1) {System.out.println("Congratulations! You've guessed the number on your first attempt!");;
}
else {System.out.println("Congratulations! You've guessed the number, it took you " + cntr + " tries");}
}
}
You need to parse your input. decimalguessed is a string, and so you can't do comparisons like decimalguessed % 1.
You can convert it to an integer like this:
int guess = 0;
try {
guess = Integer.parseInt(decimalguessed);
} catch (NumberFormatException e) {
System.out.println("Your guess was not an integer: " + e.getMessage());
System.exit(1);
}
This will handle both cases where decimalguessed contains letters, and where it contains decimal points/fractions. decimalguessed is still a string, but guess now contains the integer version of it, so you can compare it to randomnumber properly. (Your loop would have never exited before, because a string is never == an integer)
Some other notes:
You should never have:
if (condition) {
return true;
} else {
return false;
}
This can always be simply replaced with
return condition;
It feels like you're very new to this. Welcome to programming!
So first, in Java generally you're not going to have all of that instantiation and variables stuff outside of your main function, unless you're going to make everything static. I would move all of that into your main function, un-static the decimalguessed variable and setup your verifyLetters function to take an argument of String decimalguessed. It may also be wise to check if the value is a number, rather than seeing if it is not a letter. There a lot of non-number, non-letter characters.
Once you've figured out that the guess is a number, you need to tell java it is one (cast it) to a decimal, then do you further comparisons against that decimal.
Darth Android also makes some good points, especially about booleans. You should never have the only result of an if/else be to return a boolean, just return the boolean. Also avoid comparisons to true/false, just do the if on the function/variable alone, or negate it with an '!' to check for false.
Good luck!

How can I check if my string is other than int's, to clarify i need to check it is not a number

... if instead of a number I get a letter, or a symbol, or 2 decimals.
I am making a change maker program in java.
Everything works good, the only thing i am confused about is checking the string to see if is invalid for my use,
I did this for when is left empty;
if (s1.isEmpty()) {
JOptionPane.showMessageDialog(null, "Invalid input! ");
System.exit(0);
}
That works perfect, now how can I do the else to check for letters or dots or symbols, anything that is not a number?
You could use regular expressions.
Here's some sample code to check for digits only (\\d) in your input string.
The code that actually checks is pattern.matcher(in).matches() and it tries to match the regular expression defined by regex
Let me know if you need more explanations
public class HelloWorld{
public static void main(String[] args) {
String regex = "\\d+";
String inputNumber = "2";
String inputDecimal = "2.0";
String inputString = "two";
String[] inputs = {inputDecimal, inputNumber, inputString };
Pattern pattern = Pattern.compile(regex);
for(String in: inputs){
System.out.print( in + " ");
System.out.print( pattern.matcher(in).matches()? "":"does not");
System.out.print( " contain integer numbers" );
System.out.println("---");
}
}
}
If you need to perform all the processing only when the String is integer why not check for integer value in the if clause and let the else clause be common for all the letter, dots, symbols and also empty.
if(s1.isNum){
//all processing here
}
else{
JOptionPane.showMessageDialog(null,"Invalid Input");
System.out.exit(0);
}
Otherwise you could also use try and catch block.
try{
int num= Integer.parseInt(s1);
//rest of the processing
}
catch(Exception e){
JOptionPane.showMessageDialog(null,"Invalid Input");
System.out.exit(0);
}
Use either according to your requirement
You could use a regular expression1 and String.matches(String) which Tells whether or not this string matches the given regular expression. \\d+ should match one or more digits. Something like
System.out.println("12".matches("\\d+"));
Prints
true
1Some people, when confronted with a problem, think
“I know, I'll use regular expressions.” Now they have two problems. --jwz
To test whether it is an integer, parse it to an int like this:
Integer.parseInt(s1)
You might also want to make use of the value returned but I don't show it here. Now you can apply try catch blocks around the method call and catch NumberFormatException like this:
try {
Integer.parseInt(s1);
//The code here will run if s1 is an integer.
} catch (NumberFormatException e) {
//this will be executed when s1 is not an integer
}
You can also extract a method from the above code. A method that returns true when the exception is not thrown. However, a disadvantage of try catch is that throwing an exception needs time and thus, it slows down your program.
To test whether the string is a letter, you loop through all the chars in the string and use one of the methods of the Character class.
boolean isLetter = true;
for (int i = 0 ; i < s1.length() ; i++) {
if (!Character.isLetter(s1.charAt(i))) {
isLetter = false;
break;
}
}
If isLetter is true, it is a letter. Again, you can also extract this as a method.
To check whether it is a symbol, use one of the methods of the Character class (again).
boolean isSymb = true;
for (int i = 0 ; i < s1.length() ; i++) {
if (!Character.isJavaIdentifierStart(s1.charAt(i))) {
isSymb = false;
break;
}
}
To check for dots in a string, just use
s1.contains(".")
Isn't that simple?
Ok, I solved the problem the following way... I took a little bit of every idea lol...
if (s1 == null) {
JOptionPane.showMessageDialog(null, "You must enter a valid integer");
System.exit(0);
}
if (s1.isEmpty()) {
JOptionPane.showMessageDialog(null, "You must enter a valid integer");
System.exit(0);
}
for (int i = 0; i < s1.length(); i = i + 1) {
if (!Character.isDigit(s1.charAt(i))) {
JOptionPane.showMessageDialog(null, "You must enter an integer value");
System.exit(0);
}
}

StringTokenizer issues with if statements

I have to tokenize a string which looks like this:
4830673048;Tony White
There must be two tokens separated by a ;
The first token must contain 10 digits, and ONLY digits
The second token may not contain digits.
private static boolean isValid(String accountLine) throws BankAccountException
{
StringTokenizer strTok = new StringTokenizer(accountLine, ";");
boolean valid = true;
if(strTok.countTokens() == 2)
{
if(strTok.nextToken().length() == 10 && strTok.nextToken().matches(".*[0-9].*"))
{
if(!strTok.nextToken().matches(".*[0-9].*"))
{
valid = true;
}
}
}
else
{
System.out.println("Invalid Bank Account info. " + strTok.nextToken());
valid = false;
}
return valid;
}
Here is the code I came up with, but it doesn't do what I expected it to do. I know the problem probably lies in my use of .nextToken(). So then my question is, what's the proper StringTokenizer method for ONLY checking the first or the second token?
Just use String.matches() with the appropriate regex and you only need one line:
return accountLine.matches("\\d{10};[^\\d]+");
Unless this is used in more than place, I would just scrap the method and use the snippet in-line.
See if this works for you:
private static boolean isValid(String accountLine) throws BankAccountException
{
StringTokenizer strTok = new StringTokenizer(accountLine, ";");
boolean valid = true;
if(strTok.countTokens() == 2)
{
String acctNum = strTok.nextToken();
String acctHolder = strTok.nextToken();
if(acctNum.length() == 10
&& acctNum.matches(".*[0-9].*")
&& !acctHolder.matches(".*[0-9].*"))
{
valid = true;
}
}
else
{
System.out.println("Invalid Bank Account info. " + strTok.nextToken());
valid = false;
}
return valid;
}
In the code you posted, you were calling nextToken two times while evaluating the first token, inadvertently moving on to the second token too soon. By assigning the values to variables first, you can easily eliminate this issue.
if(strTok.nextToken().length() == 10 && strTok.nextToken().matches(".*[0-9].*"))
{
if(!strTok.nextToken().matches(".*[0-9].*"))
{
valid = true;
}
}
Now let's look at this code. You first say strTok.nextToken().matches(".*[0-9].*") and than say !strTok.nextToken().matches(".*[0-9].*"). Just delete the inner if and try. You don't need a regex match for second token, so no action is needed for that.
I did some research and found this solid example from Mkyong whose tutorials I admire. In the tutorial he wrote:
while (st.hasMoreElements()) {
System.out.println(st.nextElement());
}
Instead of directly using nextToken().
This tutorial of Oracle gives more decent and all-around explanation. In that, nextToken() is deeply explained and exampled.
As you'll see in both examples, nextToken() and nextElement() functions both take the next token from the tokenizer. So you'll need to assign the first call of one of these functions to a variable and do controls on that. Such as:
String firstToken = st.nextToken().toString();
if(firstToken .length() == 10 && firstToken .matches(".*[0-9].*")) {
...
}
Don't forget to use toString() after nextToken().
Try this:
private static boolean isValid(String accountLine) throws BankAccountException
{
StringTokenizer strTok = new StringTokenizer(accountLine, ";");
boolean valid = true;
String bankAccount = (String)strTok.nextElement();
if(strTok.countTokens() == 2)
{
if(strTok.nextToken().length() == 10 && bankAccount.matches(".*[0-9].*"))
{
valid = true;
}
}
else
{
System.out.println("Invalid Bank Account info. " + bankAccount);
valid = false;
}
return valid;
}

Categories