Search code examples
javafileinputstream

What is the best way to read in chars from a text file while ignoring extra spaces from new lines?


I am reading in a text file with the format of a 16x16 sudoku puzzle.

For Example:

F7B-E-A-1--6---D  
-91AF-0-85D7E4-C  
05-69C---B-EA-3-  
-C-E-2-B--A-7860  
E05---2F-7---1C-  
-4-8-DC--E-593--  
-29---1-D--A-04-  
D67-A-98----B-F-  
9B-D-130C8--F5A-  
8F4569EA7D--CB--  
6A---745BFE-12D9  
7--1DBFC-A-04--E  
5-F9C-61240D-7E-  
A--7-F-DE-580-2-  
--0-5E7-F63C--14  
CE640-----7B5D9F

I'm attempting to put the values into a 2D char array, but when encountering the end of a line 3 spaces seem to be included. I've tried using various ways like BufferedReader and FileInputStream to no avail. The text files must be in that format as my professor will be testing with his own values using that format.

My code for getting the file into an ArrayList:

private static ArrayList readFile(File filename)
{
    ArrayList records = new ArrayList();
    try
    {
        FileInputStream stream = new FileInputStream(filename);

        char current;
        while(stream.available() > 0)
        {
            current = (char)stream.read();
            records.add(current);
        }
        stream.close();
        return records;
    }
    catch (Exception e)
    {
        System.err.format("Exception occurred trying to read '%s'.", filename);
        return null;
    }
}

I then use an iterator to start assigning values to the 2D array. When printing out the grid it appears fine, but when checking individual values, like grid[1][1], it's not right because of the spacing it throws in.

Is there a way to read in char by char, but avoid the 3 spaces it puts in to represent the new line?


Solution

  • Well, since you're only really interested in hexadecimal characters and -, you can just filter everything else out. The easiest way is probably to replace:

    current = (char)stream.read();
    

    with:

    current = (char)stream.read();
    while ("0123456789ABCDEF-".indexOf(current) < 0)
        current = (char)stream.read();
    

    but you may need to fiddle with error conditions to ensure it's bullet-proof.

    For example, check how many elements were added to records once your input loop finishes. If records.size() doesn't give you 256, the file was faulty.

    That would remove all formatting concerns from your file and only content will matter (if you want, you can just provide all 256 characters on a single line, for example).

    This follows the robustness principle of "be liberal in what you accept, specific in what you produce".


    You may also want to rethink your method of creating an array list from the file input and then constructing a two-dimensional array from that. It seems to me you can just create the 2D array directly with something like (pseudo-code):

    def readPuzzle(file) -> (array, error)
        set puzzle to new char[16][16]
        set row to 0, col to 0
    
        get next character from file to current
        while read okay:
            if current in "0123456789ABCDEF-":
                if row is 16:
                    return (puzzle, "too many entries in file")
                puzzle[row][col] = current
                increment col
                if col is 16:
                    increment row
                    set col to 0
        if row is not 16:
            return (puzzle, "not enough entries in file")
        return (puzzle, "okay")
    

    This basically just reads all characters from the file and adds them directly to the array if they're valid. Before adding, it checks to ensure you haven't already filled the puzzle and, after all characters are processed, it checks to ensure the whole puzzle was filled.