import java.io.*; import java.util.*; /** * Reads delimited items (numbers, words, phrases, etc.), returning one at a time. * This class combines the standard Reader and Iterator interfaces. * * @see Reader * @see Iterator * @author Robert C. Duvall */ public class Scanner extends Reader implements Iterator { ////////////////////////////////////////////////////////////// // constants public final static String WHITE_SPACE = " \t\n\r"; public final static int LOOKAHEAD_SIZE = 1048576; ////////////////////////////////////////////////////////////// // state private BufferedReader myInput; private StringTokenizer myTokenizer; private String myDelimiters; private String myItem; private String myLine; private int myNumberOfItems; ////////////////////////////////////////////////////////////// // constructors /** * Create Scanner for that reads data from console input. */ public Scanner () { this(new InputStreamReader(System.in)); } /** * Create Scanner for that reads data from a file. * * @param file specifies file that supplies data */ public Scanner (File file) { try { init(new FileReader(file), WHITE_SPACE); } catch (FileNotFoundException fne) { throw new RuntimeException("File not found " + fne); } } /** * Create Scanner for that reads data from a string. * * @param str specifies string that supplies data */ public Scanner (String str) { this(new StringReader(str)); } /** * Create Scanner for that reads data from any kind of reader (i.e., a web site). * * @param realReader specifies reader that supplies data */ public Scanner (Reader realReader) { this(realReader, WHITE_SPACE); } /** * Create Scanner for that reads data from any kind of reader (i.e., a web site) * that is delimited by given set of characters. * * @param realReader specifies reader that supplies data * @param characters set of characters on which to separate items */ public Scanner (Reader realReader, String characters) { init(realReader, characters); } ////////////////////////////////////////////////////////////// // Reader interface methods /** * Read characters into a portion of an array. This method will block until * some input is available, an I/O error occurs, or the end of the stream is * reached. * * @param cbuf destination buffer * @param off offset at which to start storing characters * @param len maximum number of characters to read * * @return number of characters read, or -1 if end of stream has been reached */ public int read (char[] cbuf, int off, int len) throws IOException { return myInput.read(cbuf, off, len); } /** * Close the stream. Once a stream has been closed, further read(), ready(), * mark(), or reset() invocations will throw an IOException. Closing a * previously-closed stream, however, has no effect. */ public void close () { try { myInput.close(); } catch (IOException e) { System.out.println(e); } } /** * Reset to beginning of data */ public void reset () { try { myInput.reset(); myInput.mark(LOOKAHEAD_SIZE); myLine = null; myTokenizer = null; myItem = null; } catch (IOException e) { System.out.println(e); } } /** * Change delimiters used to separate items * * @param characters set of characters that delimit items */ public void useDelimiter (String characters) { myDelimiters = characters; if (myLine != null) { // BUBUG: may not want entire line back ... myTokenizer = new StringTokenizer(myLine, myDelimiters); myItem = null; } } ////////////////////////////////////////////////////////////// // Iterator interface methods /** * Check if more items are available * * @return true iff there are more items */ public boolean hasNext () { try { if (myItem == null) { myItem = getNextItem(); } return myItem != null; } catch (IOException e) { return false; } } /** * Get next item, could be anything * * @return next delimited item */ public Object next () { if (hasNext()) { String current = myItem; myItem = null; return current; } else { throw new NoSuchElementException(); } } /** * Get next delimited item as a string * * @return next delimited item, must be a string */ public String nextString () { return (String)next(); } /** * Get next delimited item as an integer value * * @return next delimited whole number */ public int nextInt () { return Integer.parseInt(nextString()); } /** * Get next delimited item as an double value. * * @return next delimited real number */ public double nextDouble () { return Double.parseDouble(nextString()); } /** * Counts the number of delimited items to be scanned. * * @return number of delimited items to be scanned */ public int getNumberItems () { if (myNumberOfItems < 0) { myNumberOfItems = 0; reset(); while (hasNext()) { nextString(); myNumberOfItems++; } reset(); } return myNumberOfItems; } /** * Not implemented, throws UnsupportedOperationException * * @see UnsupportedOperationException */ public void remove () { throw new UnsupportedOperationException(); } ////////////////////////////////////////////////////////////// // Helper methods /** * If possible, get next item even if it is on another line. * Subclasses can customize how to get next item. */ protected String getNextItem () throws IOException { while (myTokenizer == null || !myTokenizer.hasMoreTokens()) { myLine = getNextLine(myInput); if (myLine != null) { myTokenizer = new StringTokenizer(myLine, myDelimiters); } else { return null; } } // BUGBUG: does not work if input spread over many lines return myTokenizer.nextToken(); } /** * If possible, get next line of data. * Allow subclasses to customize how to read next line. * * @return next useful line in file */ protected String getNextLine (BufferedReader input) throws IOException { String result = input.readLine(); if (result != null) { return result.trim(); } return null; } /** * Initialize all instance variables (used by all constructors). * * @param realReader specifies reader that supplies data * @param characters set of characters on which to separate items */ private void init (Reader realReader, String characters) { if (realReader instanceof BufferedReader) { myInput = (BufferedReader)realReader; } else { myInput = new BufferedReader(realReader); } try { myNumberOfItems = -1; myDelimiters = characters; myInput.mark(LOOKAHEAD_SIZE); reset(); } catch (IOException io) { throw new RuntimeException("reset not supported " + io); } } ////////////////////////////////////////////////////////////// // Main // Allow this class to be run directly by Java. // Read and echo the given file. public static void main (String args[]) { Scanner input; if (args.length == 0) { input = new Scanner(); } else { input = new Scanner(new File(args[0])); } input.useDelimiter(WHITE_SPACE); while (input.hasNext()) { System.out.print("**" + input.nextString() + "**\n"); } input.useDelimiter("\n"); input.reset(); while (input.hasNext()) { System.out.print("**" + input.nextString() + "**\n"); } input.reset(); for (int k = 0; k < input.getNumberItems(); k++) { System.out.print("**" + input.nextString() + "**\n"); } } }