I'm having trouble writing a program for my Java class. The assignment's instructions are as follows:
"File Letter Counter:
Write a program that asks the user to enter the name of a file, and then asks the user to enter a character. The program should count and display the number of times that the specified character appears in the file. Use Notepad or another text editor to create a sample file that can be used to test the program."
The text file my professor provided us to test this program has 1307 lines of randomly cased and placed letters that this program has to go through and, for whatever reason, I can't seem to get this program to work right. I've tried using things outside of what we've learned so far in class and in the book, but I'm beyond lost.
Sample input:
f
d
s
h
j
Here's my code so far (compiled in NetBeans 23):
package filelettercounter;
import java.util.Scanner;
import java.io.*;
public class FileLetterCounter {
public static void main(String[] args) throws IOException {
Scanner keyboard = new Scanner(System.in);
System.out.print("Enter the file name: ");
String filename = keyboard.nextLine();
File file = new File(filename);
Scanner inputFile = new Scanner(file);
/*
My dad, after looking at my code, said (and I'm paraphrasing)
it's basically doing a JD Vance. Is there a line? "Okay, good.
It might not even be checking for other lines, it might be
repeatedly iterating over the same line.
I almost died because of his meme comparison.
*/
do {
int counter = 0;
String line = inputFile.nextLine();
System.out.print("Enter a character: ");
String character = inputFile.nextLine();
if(line.contains(character)) {
counter++;
}
System.out.println("The character " + character + " appears " +
counter + " times in the file.");
}while(inputFile.hasNext());
inputFile.close();
}
}
The output prints all 1307 lines showing that they each appear 0 times...
Enter a character: The character f appears 0 times in the file.
Enter a character: The character d appears 0 times in the file.
Enter a character: The character s appears 0 times in the file.
Enter a character: The character h appears 0 times in the file.
Enter a character: The character j appears 0 times in the file.
...with an exception thrown most of the way down the output.
Exception in thread "main" java.util.NoSuchElementException: No line found
at java.base/java.util.Scanner.nextLine(Scanner.java:1660)
at filelettercounter.FileLetterCounter.main(FileLetterCounter.java:31)
The output I need to achieve is something like this:
Enter the file name: "filename"
Enter a character: "character"
The character (character) appears (number of times) times in the file.
Regarding input from any of you who are infinitely more experienced than I am, I'm not supposed to be doing anything fancy. The farthest we've gotten through as a class has been the various loops (for, if/else if/else, do-while, while), accumulating variables, etc. It is as basic as basic gets. So, please no lists or arrays or delimiters, or anything crazy like that.
Edit:
I solved my problem and got the program working. If, for any reason, someone in the future comes along and needs a solution like this, I'll post the code that I have that now works as intended (with some added comments):
package filelettercounter;
import java.util.Scanner;
import java.io.*;
public class FileLetterCounter {
public static void main(String[] args) throws IOException, FileNotFoundException{
File file;
Scanner fileScanner;
String filename;
Scanner keyboard = new Scanner(System.in);
System.out.print("Enter file name: ");
filename = keyboard.nextLine();
//I needed to store the character value BEFORE
//switching to the File Scanner.
System.out.print("Enter a character: ");
String character = keyboard.nextLine();
file = new File(filename);
if(!file.exists()) {
System.out.println("The file does not exist.");
System.exit(0);
}
fileScanner = new Scanner(file);
if(!fileScanner.hasNextInt()) {
System.out.println("Error with file structure.");
System.exit(0);
}
/*
I didn't need the do-while loop, either. At the time of
the original code, I was throwing things into the code to
see what would work and crossing my fingers.
It took me a while to figure this part out, as well.
I didn't think having an int variable and a separate
String variable would work as intended, but it worked
(don't ask me why I thought this, I just did).
*/
int lines = fileScanner.nextInt();
fileScanner.nextLine();
int counter = 0;
for(int i = 0; i < lines; i++) {
String line = fileScanner.nextLine();
if(line.contains(character) && character.equalsIgnoreCase(character)) {
counter++;
}
}
System.out.println("The character " + character + " appears " + counter
+ " times.");
}
}
I appreciate everyone's input; it did help.
Let's start with the error;
It's decently descriptive with No line found
.
Your code at FileLetterCounter.java:31
is probably not the same line in your example, I'll assume it points to the inputFile.nextLine();
line.
This line is the place the issue is happening in your code so it's a good idea to start there.
Next we see the method call that is throwing within your code, Scanner.nextLine()
. The docs for nextLine state the following:
public String nextLine()
Advances this scanner past the current line and returns the input that was skipped. This method returns the rest of the current line, excluding any line separator at the end. The position is set to the beginning of the next line.
Since this method continues to search through the input looking for a line separator, it may buffer all of the input searching for the line to skip if no line separators are present.
Returns: the line that was skipped
Throws:
- NoSuchElementException - if no line was found
- IllegalStateException - if this scanner is closed
Since you're seeing this error, maybe the input really doesn't have any line to be found?
Let's go over the pseudo-code:
get the file and input streams ready.
loop (at least once) while the scanner has another token in its input:
...
At this point, you should check everything is working. Maybe start by printing out each token with Scanner.next()
.
Now continuing with the pseudo-code:
loop (at least once) while the scanner has another token in its input:
set a counter to zero.
advances scanner past the current line and returns the input
prompt the user for a character.
if the collected line contains an instance of the character,
then increment counter by one.
print out the counter.
end loop and start again using the same scanner.
Here's a few questions that may help:
hasNext()
but inside the loop the entire line is consumed with nextLine()
?So in short, there are several logic errors here. The first one you're asking about is the use of the scanner. You've got another with the counter, and another potential one with how the loop is structured.
If you answer those questions and talk through some new pseudo code you should have a working solution.
When learning to coding, run often. Add 3-5 lines, maybe a println to debug, test it, and repeat.
Pseudo code is your friend. In this case, there are logic errors in a few places that would be caught by talking through what you want to do then validating the program is doing what you expect.