This assignment is very similar to how a search engine works. A search engine will read words on every page that it will include in the searches. It will store information about the words for each page. You can write a search engine to do this in many ways. One way is by seeing how many times each word appears on each page. With this information stored for each page, when a search is performed, the pages are ranked based on the number of times that word appears on the pages. For example, if we were searching for "hello" and all 5 pages that we have indexed have the word "hello" in it, but the first page had it 5 times, the second page had it 4 times, and so on, the pages should be printed to the user from page 1 to page 5 in that order, since page 1 has "hello" more frequently. This is a little more in depth than what we are doing in this class. In this class, we are going to be looking through text and indexing how many times each letter appears in the text, then writing our results to a new file. This could tell us what symbols are seen more frequently.
This homework requires skills in File I/O, from chapter 12 in Guzdial. You will need to write the following classes:
You must put a comment at the top of your code that specifies your:
real name, login name, email address, and PID. You must also include a
two-to-four sentence description of the program. Use a multi-line
comment (/* */). YOU MUST DO THIS FOR EVERY JAVA
FILE!
Comments Comments in the style detailed in the book ARE required. Your code must be properly commented to receive full credit.
This class is designed to count the number of times each letter of the alphabet occurs in the input file. We are only concerned with letters, and we make no distinction between uppercase or lowercase letters (i.e. if you see an 'A' character or an 'a' character in the file, those should both add 1 to the same counter). Since we are only counting letters, we can store these counters in an integer array that has 26 elements. We can define a mapping between letters and array indexes as follows:
A=0, B=1, ..., Y=24, Z=25
The LetterFrequencies class will have an integer array field called 'frequencies', which will store the counts of the letters seen in the file. The count for 'A' will be stored in index 0, the count for 'B' will be stored in index 1, etc.
The LetterFrequencies class should have the following methods:
letterToIndex('A') == 0
letterToIndex('a') == 0
letterToIndex('e') == 4
letterToIndex('z') == 25
letterToIndex('?') == -1
letterToIndex('#') == -1
(hint: this method might be useful for implementing other methods!)
This class is designed to perform the File I/O and use a LetterFrequencies instance to keep track of the frequencies of the letters in the file. After reading the entire input file and building the LetterFrequencies object, this class will output the list of frequencies to another file in a format detailed below.
The FrequencyCounter class should have the following methods:
The format of the input file will be as follows:
<number of lines>So an example input file could look like:
<line 1>
<line 2>
...
3
This is a Haiku.
Five, then seven, then five more.
Try it out yourself.
The method of BufferedReader that you will use to read text from the file is readLine(). This will read an entire line of the file and return it as a single String. After you read the first line of the input file, you will need to transform that String into an int using the static method Integer.parseInt, which takes a String parameter and returns an int. Then once you have this int value (call it N, for example), you can write a for-loop that will read in the remaining N lines of the file.
The format of the output file will be as follows:
a <count for 'a'>An important note is that there should NOT be a line for any letter that has a count of 0. Here is the output file for the example input file above:
b <count for 'b'>
... z <count for 'z'>
a 2
e 8
f 3
h 4
i 6
k 1
l 1
m 1
n 3
o 3
r 3
s 4
t 6
u 3
v 3
y 2
The letters in this file must be lowercase, and there should be exactly one space between the letter and the count of its frequency.
After you have finished writing the output file, the BufferedWriter must be closed (by calling the close() method on it). The outputFrequencies method should have no return value.
This assignment will deal with methods that can potentially cause exceptions to be thrown, and your code needs to handle this appropriately.
Both the reading and writing can cause exceptions to be thrown. This will occur if the system cannot open or locate the filename you give it, or if it cannot read/write the file. Because of this, you need to put a try/catch block around those calls.
In this assignment, any exception that occurs is fatal, which means that you should terminate the program if one occurs. The way to terminate a java program is to call System.exit(1). This is not a crash, it just tells the program to immediately halt.
When reading the input file, the catch blocks should have the following behavior:
When writing the output file, the catch block should have the following behavior:
Since this program is more advanced than some others you may have
written, you should put extra time into testing your code to ensure
that it can handle all of the important cases. Specifically, we will
DEFINITELY be testing the following input scenarios:
In order to help you know what the correct behavior of your program should be, we have provided a teacher's solution that you can run. If you are on ieng6, then you should be able to type "runsamplePSA1", and this will run the reference version of FrequencyCounter.
This assignment will require you to repeatedly test whether or not a given char value is a letter. An obvious (and tedious) way to do this is to have a 26-pronged if-statement that says:
if (mychar=='a') {
...
} else if (mychar=='b') {
...
} ...
A much better way to approach this is to rely on the fact that Java chars are actually numbers. In Java, every char has an associated numerical value. You can get the numerical value of a char by casting it to an int. The numbers for each char are somewhat arbitrarily chosen, except that the uppercase letters are assigned consecutively in the range 65-90, and the lowercase letters are assigned consecutively in the range 97-122.
Given this information, you should ask yourself two questions that will be relevant to this assignment:
In addition to writing the two classes described above, you will be required to submit one sample input file and one sample output file. The input file can contain any text that you like, but it must be formatted according to the style described above. The input file that you turn in must be named "input.txt".
The sample output file is just the result of running YOUR code on the sample input file you provide. It should be named "output.txt", and should be formatted according to the style described above.
We will be using a Bundle script to do automated turnin for this assignment.
On ieng6 somewhere under your home directory you need to make a folder called PSA1. All of your files for this assignment must go in this folder. The files you need to turn in are:
Here are several examples of the expected input/output behavior that your code should have. For each of these examples, your code should print EXACTLY the same output.
(when there is no input.txt file)
> java FrequencyCounter
Error opening file
(when input.txt file does not start with a number)
> java FrequencyCounter
Error reading from file
(suppose that input.txt contains the following text1before the program is run)
aAbB
> java Frequency
>
(program has no printed output)
(final contents of output.txta 2after the program is run)
b 2
(suppose that input.txt contains the following text3before the program is run)
a b c d e
1 2 3 4 5
z y x w v
> java Frequency
>
(program has no printed output)
(final contents of output.txta 1after the program is run)
b 1
c 1
d 1
e 1
v 1
w 1
x 1
y 1
z 1