// ACMIO.java import java.io.FileReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.IOException; import java.io.PushbackReader; import java.text.NumberFormat; /***************************************************************************** * The ACMIO class has methods for reading some primitive data values * from the keyboard and text files, and it has methods to set fieldwidth * and precision in formatting Strings for output. The class was designed * for use in the ACM Mid-Central Regional Competition, November 6, 1999. * See the sample program ACMIOTest.java and sample input file t.txt. *

* Input method overview

* *
* There is a constructor that takes a filename as parameter. For example
* *
             * ACMIO fileIn = new ACMIO("problem1.in"); *
You may instantiate multiple file readers. There is only one keyboard, * so a static method returns the only keyboard reader. For example: *
             * ACMIO stdin = ACMIO.getStdin(); *
* IOExceptions and input in illegal formats cause the program to terminate * with an error message to System.err. The illegal input formats are caused * by incorrect numeric format or end-of-file where a token was expected.
* *
* Most reading methods skip initial whitespace, but there are two methods * that do not:
* *
             * getChar() reads the next character, and * *
             * getLine() reads a whole line. * *
* Methods with names in the form typeRead skip whitespace and then read an * int, long, double, char or String. Examples are * intRead() andstringRead(). * Note all start with a lowercase letter. Method stringRead() reads * the longest String with no whitespace. There are also methods with "ln" * added to the end:  intReadln(), longReadln(), doubleReadln(), * charReadln() and stringReadln(), which all skip the rest * of the line.
* *
* Note the distinction between that getLine() and * stringReadln().   * Both end up after the end of a line, but getLine() returns the * rest of the current line, and stringReadln()skips all whitespace, * possibly through several empty lines, and skips to the end of the line * afterthe first sequence of non-whitespace characters it finds.
* *
* Boolean methods that test the state are isEOLN() and * isEOF(), which read ahead to see if the end of a line or the * end of the file is next.
* *
* Void input skipping methods are skipBlanks(), * skipWhitespace(), and skipLine().
* *

* String formatting method overview:

* *
* To be comparable with output formatting in Pascal and C and C++, there * are a group of overloaded static methods to specify the precision of a * double and the minimum fieldwidth and left or right justification for any * String.
* *

String format(long l, int minimumWidth) *
String format(Object o, int minimumWidth) *
String format(double d, int minimumWidth) *
String format(double d, int minimumWidth, int precision) *

where a positive minimumWidth means right-justify and negative * means left-justify, and both are in a field of at least |minimumWidth| * columns. *
Explicit overloadings for the justification are only given for numbers * and for objects, but anything can be converted to a String Object by concatenating * it with the empty String: "" + (anything). Examples: *

format(123.45678, 7, 2) returns " 123.46", with one * blank on the left. *
format(123.45678, -7, 2) returns "123.46 ", with * one blank on the right. *
format(-1234, 8) returns "   -1234", with * three blanks on the left. *
format("abc", -5) returns "abc  ", with two * blanks on the right. * * @author * Andrew Harrington (anh@cs.luc.edu) * * @version * Sept 16, 1999 ****************************************************************************/ public class ACMIO { private static ACMIO stdin = null; private PushbackReader in; final static int EOF = -1; // Returned by in.read() at EOF /** * Construct an ACMIO to read from a file. * @param * filename file to read from. *

Abort * if the file cannot be opened to read. **/ public ACMIO(String filename) { try { in = new PushbackReader(new FileReader(filename)); } catch (Exception e) { badExit("can't open file " + filename); } } private ACMIO() { in = new PushbackReader(new InputStreamReader(System.in)); } /** * Returns the ACMIO object that reads from System.in. * @param none * @return * ACMIO object that reads from System.in **/ public static ACMIO getStdin() { if (stdin == null) stdin = new ACMIO(); return stdin; } /** * Read and discard whitespace: blanks, tabs, and newlines. * @param none **/ public void skipWhitespace() { unread(pastWhitespace()); } /** * Read and discard blanks. * @param none **/ public void skipBlanks() { int next = read(); while (' ' == next) next = read(); unread(next); } /** * Read and discard the rest of the current input line. * @param none **/ public void skipLine() { int next = read(); while (next != '\n' && next != EOF) next = read(); } /** * Read until the end of the current line. * @param none * @return * a String with all characters other that '\r' or '\n' * until the end of the line, or end-of-file if that comes first. **/ public String getLine() { StringBuffer buffer = new StringBuffer(80); int next = read(); while (next != '\n' && next != EOF) { if (next != '\r') buffer.append((char)next); next = read(); } return buffer.toString(); } /** * Read a character. * @param none * @return * a character read * *
Abort * if tried to read at end-of-file. **/ public char getChar() { int next = read(); if (next == EOF) badExit("expected char, not EOF!"); return (char) next; } /** * Skip whitespace and read a character. * @param none * @return * a character read that is not whitespace * *
Abort * if there was only whitespace until the end-of-file. **/ public char charRead() { int next = pastWhitespace(); if (next == EOF) badExit("expected char, not EOF!"); return (char) next; } /** * Skip whitespace, read a character, and skip the rest of the line. * @param none * @return * a character read that is not whitespace * *
Abort * if there was only whitespace until the end-of-file. **/ public char charReadln() { char answer = charRead(); skipLine(); return answer; } /** * Read a double number. * @param none * @return * a double number that's been read *
Parsing details: Skip whitespace and then read * an optional sign, 0 or more digits, an optional '.' * and 0 or more digits, and an optional exponent * including an 'e' or 'E', optional sign, and digits. * The first character not fitting this pattern is left in the input stream. * The extracted string is converted using Double.valueOf. *
Abort * if the conversion to a double causes an exception. **/ public double doubleRead() { StringBuffer input = new StringBuffer(); StringBuffer buffer = new StringBuffer(80); int next = findInteger(pastWhitespace(), buffer); if (next == '.') { // Read the decimal point and fractional part. buffer.append('.'); next = findDigits(read(), buffer); } if (next == 'E' || next == 'e') { buffer.append('E'); next = findInteger(read(), buffer); } unread(next); // only private methods end up reading ahead double d = 0.0; try { d = Double.valueOf(buffer.toString()).doubleValue(); } catch (NumberFormatException e) { badExit("bad double format!"); } return d; } /** * Read a double value from a complete line. * @param none * @return * a double value that's been read *
Note:
* This method is identical to doubleRead() with * skipLine() called just before returning. **/ public double doubleReadln() { double answer = doubleRead(); skipLine(); return answer; } /** * Read an int value. * @param none * @return * an int that has been read *
Parsing details: Skip whitespace and then read * an optional sign and digits. * The first character not fitting this pattern is left in the input stream. * The extracted string is converted using Integer.parseInt. *
Abort * if the conversion to an int causes an exception. **/ public int intRead() { StringBuffer buffer = new StringBuffer(80); unread(findInteger(pastWhitespace(), buffer)); int i = 0; try { i = Integer.parseInt(buffer.toString()); } catch (NumberFormatException e) { badExit("bad int format!"); } return i; } /** * Read an int value from a complete line. * @param none * @return * an int that has been read *
Note:
* This method is identical to intRead() with * skipLine() called just before returning. **/ public int intReadln() { int answer = intRead(); skipLine(); return answer; } /** * Read a long value. * @param none * @return * a long value that has been read *
Parsing details: Skip whitespace and then read * an optional sign and digits. * The first character not fitting this pattern is left in the input stream. * The extracted string is converted using Long.parseInt. *
Abort * if the conversion to a long causes an exception. **/ public long longRead() { StringBuffer buffer = new StringBuffer(80); unread(findInteger(pastWhitespace(), buffer)); long l = 0; try { l = Long.parseLong(buffer.toString()); } catch (NumberFormatException e) { badExit("bad long format!"); } return l; } /** * Read a long value from a complete line. * @param none * @return * a long value that has been read *
Note:
* This method is identical to longRead() with * skipLine() called just before returning. **/ public long longReadln() { long answer = longRead(); skipLine(); return answer; } /** * Read the next whitespace-delimited String. * @param none * @return * a String of non-whitespace characters read *
Abort * if there are no non-whitespace characters until end-of-file. **/ public String stringRead() { StringBuffer buffer = new StringBuffer(80); int next = pastWhitespace(); while (next != EOF && !Character.isWhitespace((char)next)) { buffer.append((char)next); next = read(); } unread(next); if (buffer.length() == 0) badExit("expected non-whitespace char, not EOF!"); return buffer.toString(); } /** * Read the next whitespace-delimited String, * and skip the rest of the line it is on. * @param none * @return * a String of non-whitespace characters read *
Abort * if there are no non-whitespace characters until end-of-file. **/ public String stringReadln() { String s = stringRead(); skipLine(); return s; } /** * Determine whether the last character of the file has been read. * @param none * @return * true if all characters up to but not necessaily including EOF have been read. **/ public boolean isEOF() { int next = read(); unread(next); return next == EOF; } /** * Determine whether the next input character is an end of line or end of file. * @param none * @return * true if the next input character is '\n' or '\r', * or if isEOF() **/ public boolean isEOLN() { int next = read(); unread(next); return (next == '\n') || (next == '\r' || next == EOF); } //private input methods ------------------------------------------------------------ private static void badExit(String errMsg) { // abort with message System.err.println("Aborting -- " + errMsg); System.exit(-1); } private int read() // Read and return the next character or abort. { int next = 0; try { next = in.read(); } catch (IOException e) { badExit("File reading error! " + e.getMessage()); } return next; } private void unread(int next) // Unread next or abort. { if (next == EOF) return; try { in.unread(next); } catch (IOException e) { badExit("File unreading error! " + e); } } private int findDigits(int next, StringBuffer buffer) // append any digits, starting with next to buffer, return first non-digit { while (Character.isDigit((char)next)) { buffer.append((char)next); next = read(); } return next; } private int findInteger(int next, StringBuffer buffer) // append any sign+digits, starting with next to buffer, // return first char not matching pattern { if (next == '+') next = read(); if (next == '-') { buffer.append('-'); next = read(); } return findDigits(next, buffer); } private int pastWhitespace() // Read and discard whitespace: blanks, tabs, and newlines. // return first non-whitespace char { int next = read(); while (Character.isWhitespace((char)next)) next = read(); return next; } // String formatting routines ---------------------------------------------- private static NumberFormat numForm = NumberFormat.getNumberInstance(); /** * Format a double as a String with a specified format. * @param d * the number to be printed * @param minimumWidth * |minimumWidth| is the minimum number of characters in the entire * output, and the positive or negative sign indicates right or left * justification. * @param fractionDigits * the number of digits to print, with rounding, on the right side * of the decimal point. A negatine fractionDigits is treated like 0. * No decimal point is printed if fractionDigits is 0. **/ public static String format(double d, int minimumWidth, int fractionDigits) { numForm.setGroupingUsed(false); // no commas if (fractionDigits < 0) fractionDigits = 0; numForm.setMinimumFractionDigits(fractionDigits); numForm.setMaximumFractionDigits(fractionDigits); return format(numForm.format(d), minimumWidth); } /** * Create a left or right justified String from an Object . * @param o * the Object to be printed * @param minimumWidth * |minimumWidth| is the minimum number of characters in the entire * output, and the positive or negative sign indicates right or left * justification. **/ public static String format(Object o, int minimumWidth) { String s = o.toString(); int nBlanks = Math.abs(minimumWidth) - s.length(); if (nBlanks <= 0) return s; String BLANK40 = " "; String pad = ""; while (nBlanks >= 40) { pad += BLANK40; nBlanks -= 40; } pad += BLANK40.substring(0,nBlanks); if (minimumWidth > 0) return pad+s; else return s+pad; } /** * Create a left or right justified String from a double value. * @param d * the number to be printed * @param minimumWidth * |minimumWidth| is the minimum number of characters in the entire * output, and the positive or negative sign indicates right or left * justification. **/ public static String format(double d, int minimumWidth) { return format(""+ d, minimumWidth); } /** * Create a left or right justified String from a long value. * @param n * the number to be printed * @param minimumWidth * |minimumWidth| is the minimum number of characters in the entire * output, and the positive or negative sign indicates right or left * justification. **/ public static String format(long n, int minimumWidth) { return format("" + n, minimumWidth); } }