I have an assignment where I am supposed to get a user input file with data in it, like below:

Billy Bob 98.6 98.6 98.6 100 200 300 400 500 600 700 800 900 110 220 330 440 550 660 770 880 990 111 222 333 444 555 666 777 888 999 average 97.6
William R. Bob 98.6 101.3 98.6 101.3
98.6 101.3
average
99.9
Willy
Bob
98 101.1 101.2 103.1
Alphonse Lucius Horatio
Williams Bob
99.1 99.2 99.3 99.4 99.5 99.6 99.7 99.8 98.1 98.2 99.9
avERagE 100.1

From there we have to format the data like below:

Enter name of file: b.txt
===========================================================================

Billy Bob: 98.6 98.6 98.6 100.0 200.0 300.0 400.0 500.0 600.0
700.0 800.0 900.0 110.0 220.0 330.0 440.0 550.0 660.0
770.0 880.0 990.0 111.0 222.0 333.0 444.0 555.0 666.0
777.0 888.0 999.0
--Average: 491.3(*)
---------------------------------------------------------------------------

William R. Bob: 98.6 101.3 98.6 101.3 98.6 101.3
--Average: 99.9
---------------------------------------------------------------------------

Willy Bob: 98.0 101.1 101.2 103.1
--Average: 100.8
---------------------------------------------------------------------------

Alphonse Lucius Horatio Williams Bob: 99.1 99.2 99.3 99.4 99.5
99.6 99.7 99.8 98.1 98.2
99.9
--Average: 99.2(*)
---------------------------------------------------------------------------

File Statistics
---------------
Total patient records: 4
Total body temp readings: 51

Not only that but we have to calculate the "average" for a person's records and also find how many patients there are and total number of records. We also have to find the average for each person, barring those that have a "average" record in the file. If there is a average already we still have to calculate it and compare to the one in the file and see if it is correct or not.

For the most part I have the user input of a file and tokenizing the data done, but I need help/explanations on how to do the rest. I have attached what I have for code so far. It's not much(compared to what I need to do), so I was wondering if someone could explain what I need to do get the output results like the example output.

Here is what I have so far:

// Assignment 1, Jan 29
// read data from a user specified file, then print; name, numbers and average



import java.io.*;
import java.util.*;

public class Assign1
   {
      public static void main(String [] argas)
         {
            String filename = getFilename();

            FileReader fr = null;
            BufferedReader br = null;
            double total = 0.0;
            

            try
               {
                  fr = new FileReader(filename);
                  br = new BufferedReader(fr);
                  String aline = br.readLine();
                  while (aline != null)

                     {
                        total = total + doublesFromLine(aline);
                        aline = br.readLine();
                     }
                  System.out.println("Total from file: " + total);
               }

            catch (Exception fx)
               {
                  if (fx instanceof FileNotFoundException)
                     System.out.println("File not found, terminating");
                  else if (fx instanceof IOException)
                     System.out.println("readLine() failed..terminating");
                  System.exit(0);
               }

      }

// return total of all doubles in the string
private static double doublesFromLine(String s)
     {
	double k = 0.0;
	StringTokenizer st = new StringTokenizer(s);
	while(st.hasMoreTokens())
		{
			String ss = st.nextToken();
			if(isDouble(ss))
		{								
		       k+=Double.parseDouble(ss);					
		}
		       System.out.print(ss + " ");
		}
		       return k;
     }

// determine if the string is a valid double string
private static boolean isDouble(String s)
     {
	try
	{
		double d = Double.parseDouble(s);
		return true;
	}
	catch (NumberFormatException nfx)
	{
		return false;
	}
				
}

// get the file name
private static String getFilename()
         {
            String filename = kbdInput("Enter file name: ");
            return filename;
         }

	  private static String kbdInput(String prompt)
         {
            String s = "";

            System.out.print(prompt);

            try
               {
                  BufferedReader kbd = new BufferedReader(new InputStreamReader(System.in));
                  s = kbd.readLine();
               }
            catch (IOException iox)
               {
                  System.out.println("Lost the keyboard...");
                  System.out.println("...terminating");
                  System.exit(0);
               }
            return s;
         }  // end of kbdInput()

   }

Do these records have a particular format, are they line separated ? as in one record per line ? If yes then you could read the file line by line and use the appropriate splitting criteria to get individual tokens. If not then you first need to establish a format of your own through which you cold filter the entries. Since in the case that a single record entry could span multiple lines, you have no way to tell the end of record, apart from identifying a string which is not equal to ("average") and assuming it to the name of the next person in which case you could mostly assume that the first record has ended. I say "mostly assume" because this may not necessarily suggest the start of a new record and could may as well be some other chars. Also as you mention the occurrence of the "average" flag is not certain which could have confirmed the end of the previous record.

Do these records have a particular format, are they line separated ? as in one record per line ? If yes then you could read the file line by line and use the appropriate splitting criteria to get individual tokens. If not then you first need to establish a format of your own through which you cold filter the entries. Since in the case that a single record entry could span multiple lines, you have no way to tell the end of record, apart from identifying a string which is not equal to ("average") and assuming it to the name of the next person in which case you could mostly assume that the first record has ended. I say "mostly assume" because this may not necessarily suggest the start of a new record and could may as well be some other chars. Also as you mention the occurrence of the "average" flag is not certain which could have confirmed the end of the previous record.

No, the records are in to particular format besides: Name, followed by data(numbers), and either a average or no average. The program is supposed to take in any type of file that follows the Name,data,average and format it accordingly.

You are right when you say that the word "average" might not mean the end of a previous record, example being person by the name of "average Joe".

I know in theory what to do, just not how. I had an idea of using states to go through the data, but I don't know how to attach data to a specific name.

I do have guidelines on how I'm supposed to do this:

  1. Reading data from file by looping through the lines and extracting it and printing it.
  2. No accumulating anything besides the totals for each person.

For a very high level break down on the records consider them to be following this format:

Name | {Data Number}+ | ["average" {number}1]

Basically, name, followed by one or more occurrences of data numbers, optionally followed by the occurrence of the string "average" along with exactly one numerical value.

Now you could break each of these entries further for example, the entry Name has a format of {a-zA-Z}+." ".{a-zA-Z}+ which is 1 or more occurrences of characters followed by space followed by another 1 or more occurrences of characters. The data numbers entry could be formatted as {{0-9}." "}1 which is one or more occurrences of digits followed by a space character.

You would need to form a regex pattern for all indivuidual entries on a similar basis and then filter out those lines which do not follow this pattern, the lines that follow the pattern will then have to be splitted/tokenized accordingly. The formats provided here are not exactly the regex patterns, those you'll have to work out on your own, but this one of the ways you could sort this.

For a very high level break down on the records consider them to be following this format:

Name | {Data Number}+ | ["average" {number}1]

Basically, name, followed by one or more occurrences of data numbers, optionally followed by the occurrence of the string "average" along with exactly one numerical value.

Now you could break each of these entries further for example, the entry Name has a format of {a-zA-Z}+." ".{a-zA-Z}+ which is 1 or more occurrences of characters followed by space followed by another 1 or more occurrences of characters. The data numbers entry could be formatted as {{0-9}." "}1 which is one or more occurrences of digits followed by a space character.

You would need to form a regex pattern for all indivuidual entries on a similar basis and then filter out those lines which do not follow this pattern, the lines that follow the pattern will then have to be splitted/tokenized accordingly. The formats provided here are not exactly the regex patterns, those you'll have to work out on your own, but this one of the ways you could sort this.

I should let you know I am a beginner in Java and have not learned any thing related to what you mentioned in class yet. I don't think I can use code or programming that I haven't learned yet.

Nevermind we'll help you solve this problem and by the end of it you'll sure have gone a micro step further. The Regular Expressions Tutorial is one of the best from the Java Tutorials section. Also use the File tutorial to get yourself acquainted with reading/writing files.

Use the Tutorials and the Java API Docs heavily especially since you are a beginner to get yourself rolling. What else will help is writing hundreds of programs.

// Assignment 1, Jan 29
// read a bunch of stuff from a file and print out the data

import java.io.*;
import java.util.*;

public class Assign1
{
	private static boolean preceededByWordAverage = false;
	private static boolean preceededByName = false;

	public static void main(String [] argas)
	{
		String filename = getFilename();

		FileReader fr = null;
		BufferedReader br = null;
		int totalTemps = 0, totalPatients = 0;


		try
		{
			fr = new FileReader(filename);
			br = new BufferedReader(fr);
			String aline = br.readLine();
			while (aline != null)
			{
				totalTemps = totalTemps + getTotalTempRecords(aline);
				aline = br.readLine();
			}

			preceededByWordAverage = false;
			preceededByName = false;

			fr = new FileReader(filename);
			br = new BufferedReader(fr);
			aline = br.readLine();
			while (aline != null)
			{
				totalPatients = totalPatients + getTotalPatients(aline);
				aline = br.readLine();
			}

                        System.out.println("Printing Data..");
                        printData(aline);
                        
			System.out.println("Total patients from file: " + totalPatients);
			System.out.println("Total temp records from file: " + totalTemps);
			}

		catch (Exception fx)
		{
			if (fx instanceof FileNotFoundException)
				System.out.println("File not found, terminating");
			else if (fx instanceof IOException)
				System.out.println("readLine() failed..terminating");
			System.exit(0);
		}

	}

	// return the total temp. records in the file
	private static int getTotalTempRecords(String s)
		{
			int k = 0;

			StringTokenizer st = new StringTokenizer(s);

			while(st.hasMoreTokens())
			{
				String ss = st.nextToken();

				ss = ss.trim();

				if (ss.compareToIgnoreCase("AVERAGE") == 0)
				{
					preceededByWordAverage = true;
					continue;
				}

				if(isDouble(ss) && !preceededByWordAverage)
				{
					k++;
				}

				preceededByWordAverage = false;

			}
			return k;
		}

	// get total number of patients in file
	private static int getTotalPatients(String s)
	{
		int k = 0;

		StringTokenizer st = new StringTokenizer(s);

			while(st.hasMoreTokens())
			{
				String ss = st.nextToken();

				ss = ss.trim();

				if(!isDouble(ss))
				{
					if (preceededByWordAverage && !preceededByName)
					{
						k++;
						preceededByName = true;
						continue;
					}

					if (ss.compareToIgnoreCase("AVERAGE") == 0)
					{
						preceededByWordAverage = true;
						continue;
					}

					if (!preceededByName && !preceededByWordAverage)
					{
						k++;
					}

					preceededByName = true;
					continue;
				}

			preceededByName = false;
			preceededByWordAverage = false;

			}
		return k;
	}

	// determine if the selected token is a double
	// or not
	private static boolean isDouble(String s)
	{
		try
		{
			double d = Double.parseDouble(s);
			return true;
		}
		catch (NumberFormatException nfx)
		{
			return false;
		}

	}

	// get the file name from user
	private static String getFilename()
	{
		String filename = kbdInput("Enter file name: ");
		return filename;
	}

	// method for user input
	private static String kbdInput(String prompt)
	{
		//return "C:\\c.txt";

		String s = "";

		System.out.print(prompt);

		try
		{
			BufferedReader kbd = new BufferedReader(new InputStreamReader(System.in));
			s = kbd.readLine();
		}
		catch (IOException iox)
		{
			System.out.println("Lost the keyboard...thank you MicroSoft");
			System.out.println("...terminating");
			System.exit(0);
		}
		return s;
	}


	private static void printData(String s)
	{
		try
		{
			/*while (s != null)
			{
				s = br.readLine();
			}*/

			StringTokenizer st = new StringTokenizer(s);

			int state = 1;

			double patientTempTotal = 0.0;

			while(st.hasMoreTokens())
			{
				String ss = st.nextToken();
				double sp = 0.0;

				if(state==1)
				{
					if(!isDouble(ss))
					{
						state = 2;
						System.out.println(ss + " ");
					}
				}
				else if(state==2)
					{
						if(!isDouble(ss))
						{
							state = 2;
							System.out.print(ss + ": ");
						}
						else if(isDouble(ss))
						{
							state = 3;
							System.out.print(ss + " ");
							sp = Double.parseDouble(ss);
							patientTempTotal = patientTempTotal + sp;
						}
					}
				else if(state==3)
					{
						if(isDouble(ss))
							{
								state = 3;
								sp = Double.parseDouble(ss);
								patientTempTotal += sp;
								System.out.print(ss + " ");
							}
						else if(!isDouble(ss) && !ss.equals("Average"))
							{
								state = 2;
								System.out.println(ss + " ");
							}
						else if(ss=="AVERAGE")
							{
								state = 4;
								System.out.print(ss + " ");
							}
					}
				else if(state==4)
					{
						if(!isDouble(ss))
							{
								state = 2;
							}
						else if(isDouble(ss))
							{
								state = 1;
								System.out.print(ss);
							}
					}
			}
		}

		catch (Exception fx)
		{

		}

	}
}

This is how far I have progressed, I can get the total records in the file and also the total patients. But when I call the "printData" method, nothing happens because the method isn't doing anything. I'm trying to use states to print out the data in the required format.

printData():

private static void printData(String aline)
	{
		FileReader fr = null;
		BufferedReader br = null;

		try
		{
			while (aline != null)
			{
				aline = br.readLine();
			}

			StringTokenizer st = new StringTokenizer(aline);

			int state = 1;

			double patientTempTotal = 0.0;

			while(st.hasMoreTokens())
			{
				String ss = st.nextToken();
				double sp = 0.0;

				if(state==1)
				{
					if(!isDouble(ss))
					{
						state = 2;
						System.out.println(ss + " ");
					}
				}
				else if(state==2)
					{
						if(!isDouble(ss))
						{
							state = 2;
							System.out.print(ss + ": ");
						}
						else if(isDouble(ss))
						{
							state = 3;
							System.out.print(ss + " ");
							sp = Double.parseDouble(ss);
							patientTempTotal = patientTempTotal + sp;
						}
					}
				else if(state==3)
					{
						if(isDouble(ss))
							{
								state = 3;
								sp = Double.parseDouble(ss);
								patientTempTotal += sp;
								System.out.print(ss + " ");
							}
						else if(!isDouble(ss) && !ss.equals("Average"))
							{
								state = 2;
								System.out.println(ss + " ");
							}
						else if(ss=="AVERAGE")
							{
								state = 4;
								System.out.print(ss + " ");
							}
					}
				else if(state==4)
					{
						if(!isDouble(ss))
							{
								state = 2;
							}
						else if(isDouble(ss))
							{
								state = 1;
								System.out.print(ss);
							}
					}
			}
		}

		catch (Exception fx)
		{

		}

	}

Firstly this while loop from the main methodis flawed. It reads into aline till the time that it isn't null, then when finally it gets null it is passed on to the printData method. So what are you gaining from it by passing a null object.

while (aline != null)
{
totalPatients = totalPatients + getTotalPatients(aline);
aline = br.readLine();
}
System.out.println("Printing Data..");
printData(aline);

Secondly you have a similar loop in the printData method where you loop through until the aline object has null in it

while (aline != null)
{
aline = br.readLine();
}

and then when it's null you use it to create a StringTokenizer here

StringTokenizer st = new StringTokenizer(aline);

This will throw a NullPointerException now if you see your code catches an exception but never prints out the trace.

catch (Exception fx)
{
}

So you do not get an output neither an exception trace.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.