Brandon P. Brandon P. - 2 months ago 28
Java Question

Read String from .txt file into 2-Dimensional Array; Ignore spaces in quotes; use only JDK

I frequent this site a lot, but I've come across something I haven't found that I can answer. This is similar to several other posts, here, but I have not found an answer to what I am looking for.

As a note, this is part of a school course, and this is currently a standalone java class of a larger java project. Currently, I am unable to edit the .txt file, and am restricted to using ONLY the following resources:

Standard JDK resources

java.util.Scanner;
java.io.FileInputStream;
java.io.IOException;


Using the following list:

john.doe 108de81c31bf9c622f76876b74e9285f "dead man" user
jane.doe 3e34baa4ee2ff767af8c120a496742b5 "dead woman" admin
barney.rubble a584efafa8f9ea7fe5cf18442f32b07b "secret password" mod
fred.flinstone 17b1b7d8a706696ed220bc414f729ad3 "R0ck3y business" user
luke.skywalker 3adea92111e6307f8f2aae4721e77900 "usetheforce1234" mod
leah.skywalker 0d107d09f5bbe40cade3de5c71e9e9b7 "saveme" admin


Each entry is separated by a tab.

The current java code that I have, is as follows:

public static void main(String[] args) throws IOException {
FileInputStream credFile = null; // File input
Scanner inFS = null; // Scanner object

final int NUM_ROWS_CRED = 6;
final int NUM_COLS_CRED = 4;
String[][] credArray = new String[NUM_ROWS_CRED][NUM_COLS_CRED];
int i = 0; // Index variable
int j = 0; // Index variable

// Import file data from file.txt
credFile = new FileInputStream("file.txt");
inFS = new Scanner(credFile);

// Create array of file.txt
for (i = 0; i < NUM_ROWS_CRED; ++i) {
for (j = 0; j < NUM_COLS_CRED; ++j) {
credArray[i][j] = inFS.next();
}
}

// Output array to verify array stored correctly.
for (i = 0; i < NUM_ROWS_CRED; ++i) {
for (j = 0; j < NUM_COLS_CRED; ++j) {
System.out.println(credArray[i][j] + " ");
}
System.out.println("");
}

credFile.close(); //Closes file.
}


My current output looks like this:
john.doe
108de81c31bf9c622f76876b74e9285f
"dead
man"

user
jane.doe
3e34baa4ee2ff767af8c120a496742b5
"dead

woman"
admin
barney.rubble
a584efafa8f9ea7fe5cf18442f32b07b

"secret
password"
mod
fred.flinstone

17b1b7d8a706696ed220bc414f729ad3
"R0ck3y
business"
user

luke.skywalker
3adea92111e6307f8f2aae4721e77900
"usertheforce1234"
mod


Expected Output:
john.doe
108de81c31bf9c622f76876b74e9285f
"dead man"
user

jane.doe
3e34baa4ee2ff767af8c120a496742b5
"dead woman"
admin


etc...

Solutions, guidance, pointers in the right direction are all welcome. Also, please remember that I am firmly restricted to not editing the .txt file, and only used the JDK and the 3 resources listed. Thank you.

Answer

Are you familiar to regular expressions? They're key to solving your question.

Like @cricket_007 already commented, the default Scanner delimiter is whitespace. That's why the scanner splits the quoted tokens away, which is something you want the scanner NOT to do, I believe. So you have to inform the scanner how to split the input tokens.

Within a row the tokens are separated by a tab character, and the rows are divided by a line break. So you can instruct the scanner like this:

inFS.useDelimiter("[\\t\\R]");

This way, the scanner will give the quoted token as a whole. This regex means split the tokens separated by a tab character OR by any linebreak. Pattern Javadoc

If there's no linebreak in the input, the regex is simpler:

inFS.useDelimiter("\\t");

In case the use of regular expressions is not allowed, you'll have to figure out another way to handle the quoted tokens.