Search code examples
javaindexingprintfrangeout

Index Out of Range (File Reading)


I am trying to have my program read student responses to questions on a multiple-choice examination (separate file, which is included) and then print out information based on the file.

The output from program should consist of a complete listing of the students' scores (the number of correct answers, incorrect answers, and blank answers), but I get this error:

Exception in thread "main" java.lang.StringIndexOutOfBoundsException:
String index out of range: 9
at java.lang.String.charAt(String.java:658)
at ExamAnalysis.basicAnalysis(ExamAnalysis.java:38)
at ExamAnalysis.main(ExamAnalysis.java:31)

Also, how can I print a regular int using printf? Right now, I am using doubles for some variables that should be ints because I can't figure out how to printf ints.

Code:

import java.util.Scanner;
import java.util.Arrays;
import java.io.*;

public class ExamAnalysis {
    public static void main(String[] args) throws FileNotFoundException {
        Scanner keyboard = new Scanner(System.in);
        double numStudents = 0;
        System.out.print("Welcome to Exam Analysis. Let's begin ...\n"
                + "\nPlease type the correct answers to the exam questions,\n"
                + "one right after the other: ");
        // String corrAns = keyboard.next();
        String corrAns = "ABCEDBACED";
        System.out
                .print("\nWhat is the name of the file containing each student's\n"
                        + "responses to the 10 questions?");
        // File f = new File (keyboard.next());
        File f = new File("exams.dat");
        Scanner fileR1 = new Scanner(f);
        while (fileR1.hasNextLine()) {
            System.out.printf("Student #%.0f's responses: %s\n",
                    numStudents + 1, fileR1.nextLine());
            numStudents++;
        }
        System.out
                .printf("We have reached \"end of file!\"\n"
                        + "\nThank you for the data on the %.0f students. Here's the analysis:\n",
                        numStudents);
        String[] studentAns = new String[(int) numStudents];
        Scanner fileR2 = new Scanner(f);
        for (int num = 0; num < numStudents; num++) {
            String ans = fileR2.nextLine();
            studentAns[num] = ans;
        }
        int numStud = (int) numStudents;
        basicAnalysis(numStud, studentAns, corrAns);
    }

    public static void basicAnalysis(int numStud, String[] studentAns,
            String corrAns) {
        int[][] bArray = new int[numStud][3];
        for (int num = 0; num < numStud; num++) {
            String ansString = studentAns[num];
            for (int charNum = 0; charNum < corrAns.length(); charNum++) {
                if (ansString.charAt(charNum) == ' ') {
                    bArray[num][2] += 1;
                } else if (ansString.charAt(charNum) == corrAns.charAt(charNum)) {
                    bArray[num][0] += 1;
                } else {
                    bArray[num][1] += 1;
                }
            }
        }
        System.out.println(Arrays.deepToString(bArray));
        System.out.println("Student #    Correct    Incorrect    Blank\n"
                + "~~~~~~~~~    ~~~~~~~    ~~~~~~~~~    ~~~~~");
        for (int numb = 0; numb < numStud; numb++) {
            System.out.printf("%5.0f %11d %11d %8d\n", (double) numb + 1,
                    bArray[numb][0], bArray[numb][1], bArray[numb][2]);
        }
    }
}

The file that I am reading from is:

ABDEBBAC D
ABCE CACED
  DCE AEDC
ABCEB ACED
BBCEDBACED
DBCE CACED
ABCE CA E
BBE  CACED
ABCEDBACED

I am pretty sure that my method basicAnalysis works fine. May have to do with reading in blanks. Any help would be greatly appreciated. Thanks


Solution

  • Not sure I fully understand what you're trying to accomplish, but if all your records in exams.dat must have the same length, then the 3rd one from the bottom is missing a character. I'm referring to that record:

    ABCE CA E
    

    All other records are 10 characters long, but that one has only 9 chars.

    Update:

    To make it more robust, seems like you need to account for the fact that the number of answers from the student might be different than the expected (correct) answers, and both ways (i.e. student answered less OR more than expected answers).

    I would change the content of your inner for loop body to:

    if (charNum >= ansString.length()) {
                    bArray[num][2] += 1;
                } else if (ansString.charAt(charNum) == ' ') {
                    bArray[num][2] += 1;
                } else if (ansString.charAt(charNum) == corrAns.charAt(charNum)) {
                    bArray[num][0] += 1;
                } else {
                    bArray[num][1] += 1;
                }
    

    If you want to increment the number of incorrect responses if student answered more than expected, you'd just need to add after before or after your inner for loop:

    if (ansString.length() > corrAns.length())
                bArray[num][2] += (ansString.length() - corrAns.length());