Assignment 03

Task

Write a program that will count the digits in a given file.

Text:
Concepts: data types, conditionals, loops, arrays, command line arguments, file I/O, API documentation.

Steps

Your program should take the name of the text file to read as a command line argument. If no command line arguments are given, print a message explaining how to use the program and then quit.

If the file given cannot be opened or read, print an error message and quit.

If the file can be read, read in its contents and count how many times each digit (0 - 9) occurs within the file. Use an array to store these counts. Print out the count for only each digit that occurs at least once in the file. Print only one digit and its corresponding count per line. Also print the total number of digits in the file.

You should be able to write this program without using a 10-case switch or 10 if/else-ifs to translate the digits from characters to ints or to compute the array index corresponding to a particular digit.

Sample Output

The following is taken from the command line and shows me running the program 6 separate times. The grey line is my prompt, and is not part of the program output.

C:\Files\webwork\UH\teaching\ics211\grading\A03>java ZtomaszeA03
This program counts the digits in a given file.
You must specify the filename as a command line argument.

Example: java ZtomaszeA03 pi.txt

C:\Files\webwork\UH\teaching\ics211\grading\A03>java ZtomaszeA03 nodigits.txt
Count of digits found in nodigits.txt:


Total digits found: 0

C:\Files\webwork\UH\teaching\ics211\grading\A03>java ZtomaszeA03 lonedigit.txt
Count of digits found in lonedigit.txt:

1: 1

Total digits found: 1

C:\Files\webwork\UH\teaching\ics211\grading\A03>java ZtomaszeA03 md5sum.txt
Count of digits found in md5sum.txt:

1: 1
2: 4
4: 2
5: 1
6: 1
8: 1
9: 6

Total digits found: 16

C:\Files\webwork\UH\teaching\ics211\grading\A03>java ZtomaszeA03 access.log
Count of digits found in access.log:

0: 2669
1: 2955
2: 1808
3: 760
4: 497
5: 982
6: 560
7: 868
8: 611
9: 365

Total digits found: 12075

C:\Files\webwork\UH\teaching\ics211\grading\A03>java ZtomaszeA03 pi.txt
Count of digits found in pi.txt:

0: 99959
1: 99758
2: 100026
3: 100230
4: 100230
5: 100359
6: 99548
7: 99800
8: 99985
9: 100106

Total digits found: 1000001

You can download most of these files here. For pi.txt, I just copied the digits provided here into a text file.

What to Submit

Upload your UsernameA03.java file to Tamarin.

Remember to follow the course coding standards on all assignments.

Grading [50 points]

5 - Compiles
10 - Command line args
Gets name of file-to-read from command line arguments (7). Usage message (and no other output) if no command line argument given (3).
5 - Appropriate error message (and no other output) if given file cannot be found or read.
25 - Correct output
Prints correct counts for each digit (0 to 9) found in file, one per line (20). Does not print results for digits with 0 counts (-5 if so). Prints correct total number of digits, labelled as total, count, or sum (5).
5 - Required internals
Uses an int array of size 10 (3). Does not use 10 ifs or switch cases (2).

FAQs

This program is hard! What do I do if I don't know how to write this?
Your code does not need to be long. Mine is about 50 lines, including all documentation and error-handling. The part that actually reads from the file, totals the digits found, and prints the results is about 25 lines.

The hard part is the design: breaking the problem down into smaller pieces. As we did in lecture 02A, take it one step at a time, breaking each step down into smaller and smaller pieces until you can turn each piece into code.

Also, depending on your 111 experience, you may not be very familiar with file I/O or command line arguments. If so, you may also have to do a bit of research to figure what methods you'll need to use some of the steps in your design. Some of the following FAQs should point you in the right direction with that.

How do I read from a file?

I find that using a Scanner is an easy way to do this, as shown on this slide.

There are other ways to read in a file though. You can use whatever approach works for you.

But I just want the digits out of the file. So I should use Scanner's nextInt(), right?
Probably a bad idea. Think about how nextInt() works when you're reading from the keyboard: it gives you the entire number the user typed, not just one digit at a time. If you use nextInt() to read from the file, you'll then have to break any multi-digit numbers back into component digits somehow. Also, what will nextInt() do with a word that's a mix of letters and numbers? There's probably an easier approach...
I could use Scanner's next() method to read the file one word at a time...

Again, not really much help since you still need to pick the digits out of the individual words.

Now, there is a way to change Scanner's default behavior. Each time you call next(), the Scanner skips over the next sequence of delimiter characters and then grabs the next token. By default, the delimiter is defined as any whitespace characters: space, tab, newline, etc. However, it is possible to change the delimiter to "" (the empty string). Then, each time you call next(), the Scanner won't skip anything, but just give you the next character as a String of length 1. Examine the API for a method that would let you change a Scanner object's delimiter.

Alternatively, you could use the BufferedReader approach. A BufferedReader has a read() method that will give you the next single character. (See the API for more.) However, it returns this char as an int so you can see if it's -1, which means the end-of-file has been reached. It's still really the char value though, so you'll need to covert it to the corresponding int value somehow.

How do I read in the file one character at a time?
See above FAQ.
Hmm, reading in single characters or numbers is rather complicated. I usually just read in whole lines from a file.
That's fine too. Each line is a long String then, so just find a way to loop through a String to examine each character. (Hint: The String.indexOf method would help.)
Okay, I've got a single char (either because I read it in that way or because I'm looping through a String). How do I know if this character is a digit, especially without using a bunch of ifs?
Try the Character.isDigit method. Look it up in the API for more info, but here's an example of its use:
  char letter = '9';
  if (Character.isDigit(letter)) {
    //letter is a digit
  }
Well, now I have a single letter as a char AND I know it's a digit. I'd like to turn it into its corresponding int value. How?

Casting won't work, since that would just change its data type, not its value:

  char digit = '9';
  int val = (char) digit;  //NO!  Gives you 57, the ASCII value for the character '9'

Instead, you need to convert it using a method. However, as discussed in lab, the most commonly used method for this, Integer.parseInt, takes a String, not a char. So convert the char to a String first using one of a couple different options:

  char digit = '9';
  String str = String.valueOf(digit);  //option 1
  String str = "" + digit;             //option 2
  int nine = Integer.parseInt(str);

Note that if you already know that your char is a digit (because you used Character.isDigit, for example), you don't have to use the try/catch often found around a call to Integer.parseInt. This is because you know you'll never generate a NumberFormatException in this case.