I am working on a very simple reverse polish notation calculator using stacks, and having trouble with an if/else statement inside a while loop. The rest of the code is working correctly, but I keep getting a NumberFormatException after the else line. I think this means it is not doing what it says to do in the if statement when the input is "*", but I am not sure how to fix this. Why would it go to else if the input is equal to one of the specified characters? I am not interested in making code more efficient, I would like to keep the format I have if possible, but I am very confused. Thank you so much for your help.
try {
Scanner stackScanner = new Scanner(stackFile);
while (stackScanner.hasNextLine()) {
String pls = "+";
String min = "-";
String mul = "*";
String div = "/";
String mod = "%";
String exp = "^";
//stackScanner.nextLine();
if(stackScanner.nextLine().equals(pls) ||
stackScanner.nextLine().equals(min) ||
stackScanner.nextLine().equals(mul) ||
stackScanner.nextLine().equals(div) ||
stackScanner.nextLine().equals(mod) ||
stackScanner.nextLine().equals(exp)) {
stack.push(new operationNode(stackScanner.nextLine()));
}
else {
stack.push(new
numberNode(Double.parseDouble(stackScanner.nextLine())));
}
}
stackScanner.close();
The nextLine() method of Scanner reads the next line. If you call it more than once, it will read more than one line. So this statement:
if(stackScanner.nextLine().equals(pls) ||
stackScanner.nextLine().equals(min) ||
stackScanner.nextLine().equals(mul) ||
stackScanner.nextLine().equals(div) ||
stackScanner.nextLine().equals(mod) ||
stackScanner.nextLine().equals(exp)) {
stack.push(new operationNode(stackScanner.nextLine()));
}
Here's what it does:
Reads a line, and tests if it's equal to "+". If it's not:
Reads another line, and tests if that second line is equal to "-". It doesn't test the same line that it tested against "+"--it tests the next line. If it's not "-":
Reads another line ... you get the picture.
Solution: Read the line once and save the result in a variable. (I don't know whether this will solve the entire problem. But you definitely need to fix this.)
Related
I'm sure if you read the snippet you'll understand what I'm trying to do. However, I tried it first with null and "". I think .eoln() won't work because I'm asking for multiple lines of input, of which all have an end of line. I would preferably have the loop terminate when the user returns an empty line. For some more background, I've used the ==/!= and .equals() operators/method to experiment. I also just tried a do/while to no avail.
The asterisks were added to test if the empty string was an issue for the while statement.
Can anyone explain what I clearly don't understand about Java/TextIO yet?
EDIT - Revised Code Snippet:
while(write){
pl("Begin writing content to fill file.");
pl("");
pl("Return a line with a single SPACE or");
pl("\"\\n\" to represent line breaks in your");
pl("");
pl("Return two asterisks ** when done writing,");
pl("and you will be then prompted to select a file");
pl("to save your writing to.");
String input = TextIO.getln();;
String value = new String();
while(!(input.equals(""))) {
if (input == " " || input == "\\n") {
value += "\\n" + "\\n";
} else {
value += input + " ";
} // end if/else //
input = TextIO.getln();
} // end while(input) //
TextIO.writeUserSelectedFile();
p(value);
TextIO.writeStandardOutput();
pl("Would you like to write to another file?");
Boolean cont = TextIO.getBoolean();
write = cont;
}
}
I'm making a program with Java that needs to involve some error checking. I can stop users from entering bad numerical inputs like this (assume the input scanner has already been created):
while (n == 0){
System.out.println("Can't use 0 as a denominator! Please enter a real, nonzero number");
n = input.nextInt();
}
But how do I stop users from entering an invalid string? I can't use !=, because strings can only be compared with the string.equals() method, right? So, is there a while not loop? ie:
while !(string.equals("y") || string.equals("n")){
//here have code
}
Or something of that nature?
While there is no such thing as a while-not loop, you can always invert the condition:
while (!(string.equals("y") || string.equals("n"))){
This is read, "while the string is not equal to "y" or "n"".
You could also apply DeMorgan's identity to rewrite this as:
while (!(string.equals("y")) && !(string.equals("n"))){
which is a bit clearer as "While the string isn't equal to "y" and isn't equal to "n"".
There isn't a while-not instruction, but you can simply negate the condition in a normal while loop. Try this:
while (!string.equals("y") && !string.equals("n"))
Or even better, to guard against the case where the string is null and/or it's in a different case:
while (!"y".equalsIgnoreCase(string) && !"n".equalsIgnoreCase(string))
You almost get it, just change where you position your !
like this:
while (!(string.equals("y") || string.equals("n")))
Why not try regex?
Scanner sc = new Scanner(System.in);
String string = sc.nextLine();
while (!string.matches("(?i)^(?:y|n|yes|no)$"))
{
System.out.println("Invalid input...");
string = sc.nextLine();
}
boolean answer = string.matches("(?i)^(?:y|yes)$");
I am writing a program that is going to read a string from a file, and then remove anything that isn't 1-9 or A-Z or a-z. The A-Z values need to become lowercase. Everything seems to run fine, I have no errors, however my output is messed up. It seems to skip certain characters for no reason whatsoever. I've looked at it and tweaked it but nothing works. Can't figure out why it is randomly skipping certain characters because I believe my if statements are correct. Here is the code:
String dataIn;
int temp;
String newstring= "";
BufferedReader file = new BufferedReader(new FileReader("palDataIn.txt"));
while((dataIn=file.readLine())!=null)
{
newstring="";
for(int i=0;i<dataIn.length();i++)
{
temp=(int)dataIn.charAt(i);
if(temp>46&&temp<58)
{
newstring=newstring+dataIn.charAt(i);
}
if(temp>96&&temp<123)
{
newstring=newstring+dataIn.charAt(i);
}
if(temp>64&&temp<91)
{
newstring=newstring+Character.toLowerCase(dataIn.charAt(i));
}
i++;
}
System.out.println(newstring);
}
So to give you an example, the first string I read in is :
A sample line this is.
The output after my program runs through it is this:
asmlietis
So it is reading the A making it lowercase, skips the space like it is suppose to, reads the s in, but then for some reason skips the "a" and the "m" and goes to the "p".
You're incrementing i in the each of the blocks as well as in the main loop "header". Indeed, because you've got one i++; in an else statement for the last if statement, you're sometimes incrementing i twice during the loop.
Just get rid of all the i++; statements other than the one in the for statement declaration. For example:
newstring="";
for(int i=0;i<dataIn.length();i++)
{
temp=(int)dataIn.charAt(i);
if(temp>46&&temp<58)
{
newstring=newstring+dataIn.charAt(i);
}
if(temp>96&&temp<123)
{
newstring=newstring+dataIn.charAt(i);
}
if(temp>64&&temp<91)
{
newstring=newstring+Character.toLowerCase(dataIn.charAt(i));
}
}
I wouldn't stop editing there though. I'd also:
Use a char instead of an int as the local variable for the current character you're looking at
Use character literals for comparisons, to make it much clearer what's going on
Use a StringBuilder to build up the string
Declare the variable for the output string for the current line within the loop
Use if / else if to make it clear you're only expecting to go into one branch
Combine the two paths that both append the character as-is
Fix the condition for numbers (it's incorrect at the moment)
Use more whitespace for clarity
Specify a locale in toLower to avoid "the Turkey problem" with I
So:
String line;
while((line = file.readLine()) != null)
{
StringBuilder builder = new StringBuilder(line.length());
for (int i = 0; i < line.length(); i++) {
char current = line.charAt(i);
// Are you sure you want to trim 0?
if ((current >= '1' && current <= '9') ||
(current >= 'a' && current <= 'z')) {
builder.append(current);
} else if (current >= 'A' && current <= 'Z') {
builder.append(Character.toLowerCase(current, Locale.US));
}
}
System.out.println(builder);
}
Given a File and a Scanner object,
File simpleFile = ranFi.getSelectedFile();
Scanner text = new Scanner(simpleFile);
and these two commonplace statements:
while(text.hasNext())
{
String currentLine = text.nextLine();
I'm trying to use Scanner/String class logical statements in a single if-statement clause which reads first line of file under a given matching regular expressions, such as:
String fp100 = "[S][:][A-Ze0-1]";
String fp200 = "[S][:][A-Z0-1][A-Z0-1]";
//other regexes…
and then invoke the appropriate Scanner/String class methods in same if-statement clause to read to second and onward/acceptable lines. I've read javadoc up and down but haven't figured out yet. Using currentLine.matches(regex) and text.nextLine().matches(regex), this code compiled,
if(currentLine.matches(fp100)||currentLine.matches(fp200)||
currentLine.matches(fp300) && text.nextLine().matches(fp100)||
text.nextLine().matches(fp101) || text.nextLine().matches(fp200)||
text.nextLine().matches(fp201) || text.nextLine().matches(fp300)||
text.nextLine().matches(fp301))
{
but throws an No Such Element Exception immediately. What am I doing wrong?
Thank you in advance for your time. EDIT: I've included the stack trace, but removed the source code since this is project related.
I see two problems:
When you perform the if condition, text.nextLine() may not be available.
if you mean to say, execute the if when any of the currentLine Matches + any of the nextLine match as true then wrap || arguments in a brace as:
if((currentLine.matches(fp100)||currentLine.matches(fp200)||
currentLine.matches(fp300)) &&
(text.nextLine().matches(fp100)||
text.nextLine().matches(fp101) || text.nextLine().matches(fp200)||
text.nextLine().matches(fp201) || text.nextLine().matches(fp300)||
text.nextLine().matches(fp301)))
I think you wanted to write your while loop something like this:
while(text.hasNextLine()){
String currentLine = text.nextLine();
String nextLine = "";
if(text.hasNextLine())[
nextLine = text.nextLine();
}
/**ACC conditions*/
if((currentLine.matches(fp100)||currentLine.matches(fp200)
|| currentLine.matches(fp300))
&& (nextLine.matches(fp100)|| nextLine.matches(fp101)
|| nextLine.matches(fp200)
|| nextLine.matches(fp201) || nextLine.matches(fp300)
|| nextLine.matches(fp301)) {
//current line is OK
System.out.println(currentLine);
output.write(currentLine);
output.write("\n");
abc1List.add(currentLine);
lineOK++;
//next line is OK
System.out.println(nextLine);
output.write(nextLine);
output.write("\n");
abc1List.add(nextLine);
// <-- not sure if you want OK as 1 or 2 here
lineOK++;
} /**REJ conditions*/
else if(!currentLine.matches(fp100)||!currentLine.matches(fp101)||
!currentLine.matches(fp200)||!currentLine.matches(fp201)||
!currentLine.matches(fp300)||!currentLine.matches(fp301)){
System.out.println("invalid cfg; terminating....");
System.exit(0);
}
}//end of while
Your while loop should start with while(text.hasNextLine()) if you are using text.nextLine().matches(regex) inside the loop. Be careful. If text.hasNext() evaluates to true, it doesn't mean that text.nextLine() will be non-null.
My program reads lines from a plain text file w/ lines formatted: <integer>;<integer>%n, where ; is the delimiter. It compares the two parsed integers against 2 other known values and increments tallyArray[i] if they match.
I currently use:
try {
scan = new Scanner(new BufferedReader(new FileReader("LogFileToBeRead.txt")));
for (int i = 0; i < tallyArraySize; i++) {
explodedLogLine = scan.nextLine().split(";");
if (IntReferenceVal1 == Integer.parseInt(explodedLogLine[0]) && IntReferenceVal2 == Integer.parseInt(explodedLogLine[1])) {
tallyArray[i]++;
}
}
} finally {
if (scan != null) { scan.close(); }
}
I was wondering if there were any serious faults with this method. It does not need to be production-quality.
Also, is there a standard way of parsing a string like this?
EDIT: We can assume the text file is perfectly formatted. But I see the importance for accounting for possible exceptions.
You are not handling NumberFormatExceptions thrown by the Integer.parseInt() method calls. If there's one bad line, execution exits your for loop.
You aren't vetting the integrity of the file you are reading from. If there isn't a ; character or if the Strings aren't actually numbers, execution simply exits the code block you posted.
If you can assume the file is perfectly formatted, and you're set on using a Scanner, you can add ; as a delimiter to the Scanner:
scan = new Scanner(new BufferedReader(new FileReader("LogFileToBeRead.txt")));
scan.useDelimiter(Pattern.compile("(;|\\s)"));
for (int i = 0; i < tallyArraySize; i++) {
int ref1 = scan.nextInt();
int ref2 = scan.nextInt();
if (IntReferenceVal1 == ref1 &&
IntReferenceVal2 == ref2) {
tallyArray[i]++;
}
}
And simply call Scanner.nextInt() twice for each line.
According to me There are three flaws in the program.
Delimiter ; what if there is delimiter is removed by accident or added by accident
There should be check on explodedLogLine that it is of length 2 and it is not null otherwise it will result in unexpected runtime error
You should catch NumberFormatException format exception since you can never be sure that Input is always a number
A simple illustration below gives you idea how things will go wrong.
String str = "3;;3";
System.out.println(Arrays.toString(str.split(";")));
This code will print [3, , 3] in such case your program will produce NumberFormatException as "" string can not be parsed to Integer.