then null is returned and the position of the scanner is unchanged.
Note that if the pattern does not match the entire line then the scanner will be positioned to continue reading
the remainder of the current line; and if the pattern starts in the middle of the line, then all preceding input is
skipped. As usual a second form of this method takes a String representing the pattern.
You can use a scanner's hasNextLine and nextLine methods to tokenize input a complete line at a
time. The hasNextLine method returns true if there is another line of input in this scanner. This means
that between the current position of the scanner and the end of the input there is either a line separator or one
or more other characters. The nextLine method advances the scanner to the start of the next line and returns
all the input that was skipped, excluding the line separator itself.
Consider the example of input that is in comma-separated-value format. This format is often used to export
values from a table, where each line in the output represents a row of the table and each value before a comma
(or a newline) represents the contents of a cell. With a fixed number of cells per row we can process each line
of input as a single entity:
static final int CELLS = 4;
public static List<String[]> readCSVTable(Readable source)
throws IOException {
Scanner in = new Scanner(source);
List<String[]> vals = new ArrayList<String[]>();
String exp = "^(.),(.),(.),(.)";
Pattern pat = Pattern.compile(exp, Pattern.MULTILINE);
while (in.hasNextLine()) {
String line = in.findInLine(pat);
if (line != null) {
String[] cells = new String[CELLS];
MatchResult match = in.match();
for (int i = 0; i < CELLS; i++)
cells[i] = match.group(i+1);
vals.add(cells);
in.nextLine(); // skip newline
}
else {
throw new IOException("input format error");
}
}
IOException ex = in.ioException();
if (ex!= null)
throw ex;
return vals;
}
Each line of the input is expected to have four values separated by commas (naturally you'd want to adapt the
pattern to account for different numbers of cells in different calls to the method). If the line matches what is
expected then each value is extracted from the match group. When a match is found, the newline is left in the
input so we use nextLine to skip over it. As we don't know how many lines there will be, we use a List to
accumulate the rows.
The use of a pattern in multiline mode is common when scanning line-oriented input. The pattern we used has
to match from the start of a line, so we need to include the start-of-line (^) boundary marker, and that only
matches actual lines when the pattern is in multiline mode.