content: /*
   * Copyright (C) 2014 The Android Open Source Project
   * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.  Oracle designates this
   * particular file as subject to the "Classpath" exception as provided
   * by Oracle in the LICENSE file that accompanied this code.
   *
   * This code is distributed in the hope that it will be useful, but WITHOUT
   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   * version 2 for more details (a copy is included in the LICENSE file that
   * accompanied this code).
   *
   * You should have received a copy of the GNU General Public License version
   * 2 along with this work; if not, write to the Free Software Foundation,
   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   *
   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   * or visit www.oracle.com if you need additional information or have any
   * questions.
   */
  
  package java.util;
  
  import java.nio.file.Path;
  import java.nio.file.Files;
  import java.util.regex.*;
  import java.io.*;
  import java.math.*;
  import java.nio.*;
  import java.nio.channels.*;
  import java.nio.charset.*;
  import java.text.*;
  import java.util.Locale;
  
  import sun.misc.LRUCache;
  
  /**
   * A simple text scanner which can parse primitive types and strings using
   * regular expressions.
   *
   * <p>A <code>Scanner</code> breaks its input into tokens using a
   * delimiter pattern, which by default matches whitespace. The resulting
   * tokens may then be converted into values of different types using the
   * various <tt>next</tt> methods.
   *
   * <p>For example, this code allows a user to read a number from
   * <tt>System.in</tt>:
   * <blockquote><pre>{@code
   *     Scanner sc = new Scanner(System.in);
   *     int i = sc.nextInt();
   * }</pre></blockquote>
   *
   * <p>As another example, this code allows <code>long</code> types to be
   * assigned from entries in a file <code>myNumbers</code>:
   * <blockquote><pre>{@code
   *      Scanner sc = new Scanner(new File("myNumbers"));
   *      while (sc.hasNextLong()) {
   *          long aLong = sc.nextLong();
   *      }
   * }</pre></blockquote>
   *
   * <p>The scanner can also use delimiters other than whitespace. This
   * example reads several items in from a string:
   * <blockquote><pre>{@code
   *     String input = "1 fish 2 fish red fish blue fish";
   *     Scanner s = new Scanner(input).useDelimiter("\\s*fish\\s*");
   *     System.out.println(s.nextInt());
   *     System.out.println(s.nextInt());
   *     System.out.println(s.next());
   *     System.out.println(s.next());
   *     s.close();
   * }</pre></blockquote>
   * <p>
   * prints the following output:
   * <blockquote><pre>{@code
   *     1
   *     2
   *     red
   *     blue
   * }</pre></blockquote>
   *
   * <p>The same output can be generated with this code, which uses a regular
   * expression to parse all four tokens at once:
   * <blockquote><pre>{@code
   *     String input = "1 fish 2 fish red fish blue fish";
   *     Scanner s = new Scanner(input);
   *     s.findInLine("(\\d+) fish (\\d+) fish (\\w+) fish (\\w+)");
   *     MatchResult result = s.match();
   *     for (int i=1; i<=result.groupCount(); i++)
   *         System.out.println(result.group(i));
   *     s.close();
   * }</pre></blockquote>
   *
   * <p>The <a name="default-delimiter">default whitespace delimiter</a> used
   * by a scanner is as recognized by {@link Character}.{@link
   * Character#isWhitespace(char) isWhitespace}. The {@link #reset}
   * method will reset the value of the scanner's delimiter to the default
   * whitespace delimiter regardless of whether it was previously changed.
   *
   * <p>A scanning operation may block waiting for input.
   *
   * <p>The {@link #next} and {@link #hasNext} methods and their
   * primitive-type companion methods (such as {@link #nextInt} and
   * {@link #hasNextInt}) first skip any input that matches the delimiter
   * pattern, and then attempt to return the next token. Both <tt>hasNext</tt>
   * and <tt>next</tt> methods may block waiting for further input.  Whether a
   * <tt>hasNext</tt> method blocks has no connection to whether or not its
   * associated <tt>next</tt> method will block.
   *
   * <p> The {@link #findInLine}, {@link #findWithinHorizon}, and {@link #skip}
   * methods operate independently of the delimiter pattern. These methods will
   * attempt to match the specified pattern with no regard to delimiters in the
   * input and thus can be used in special circumstances where delimiters are
   * not relevant. These methods may block waiting for more input.
   *
   * <p>When a scanner throws an {@link InputMismatchException}, the scanner
   * will not pass the token that caused the exception, so that it may be
   * retrieved or skipped via some other method.
   *
   * <p>Depending upon the type of delimiting pattern, empty tokens may be
   * returned. For example, the pattern <tt>"\\s+"</tt> will return no empty
   * tokens since it matches multiple instances of the delimiter. The delimiting
   * pattern <tt>"\\s"</tt> could return empty tokens since it only passes one
   * space at a time.
   *
   * <p> A scanner can read text from any object which implements the {@link
   * Readable} interface.  If an invocation of the underlying
   * readable's {@link Readable#read} method throws an {@link
   * IOException} then the scanner assumes that the end of the input
   * has been reached.  The most recent <tt>IOException</tt> thrown by the
   * underlying readable can be retrieved via the {@link #ioException} method.
   *
   * <p>When a <code>Scanner</code> is closed, it will close its input source
   * if the source implements the {@link Closeable} interface.
   *
   * <p>A <code>Scanner</code> is not safe for multithreaded use without
   * external synchronization.
   *
   * <p>Unless otherwise mentioned, passing a <code>null</code> parameter into
   * any method of a <code>Scanner</code> will cause a
   * <code>NullPointerException</code> to be thrown.
   *
   * <p>A scanner will default to interpreting numbers as decimal unless a
   * different radix has been set by using the {@link #useRadix} method. The
   * {@link #reset} method will reset the value of the scanner's radix to
   * <code>10</code> regardless of whether it was previously changed.
   *
   * <h3> <a name="localized-numbers">Localized numbers</a> </h3>
   *
   * <p> An instance of this class is capable of scanning numbers in the standard
   * formats as well as in the formats of the scanner's locale. A scanner's
   * <a name="initial-locale">initial locale </a>is the value returned by the {@link
   * Locale#getDefault(Locale.Category)
   * Locale.getDefault(Locale.Category.FORMAT)} method; it may be changed via the {@link
   * #useLocale} method. The {@link #reset} method will reset the value of the
   * scanner's locale to the initial locale regardless of whether it was
   * previously changed.
   *
   * <p>The localized formats are defined in terms of the following parameters,
   * which for a particular locale are taken from that locale's {@link
   * DecimalFormat DecimalFormat} object, <tt>df</tt>, and its and
   * {@link DecimalFormatSymbols DecimalFormatSymbols} object,
   * <tt>dfs</tt>.
   *
   * <blockquote><dl>
   *     <dt><i>LocalGroupSeparator&nbsp;&nbsp;</i>
   *         <dd>The character used to separate thousands groups,
   *         <i>i.e.,</i>&nbsp;<tt>dfs.</tt>{@link
   *         DecimalFormatSymbols#getGroupingSeparator
   *         getGroupingSeparator()}
   *     <dt><i>LocalDecimalSeparator&nbsp;&nbsp;</i>
   *         <dd>The character used for the decimal point,
   *     <i>i.e.,</i>&nbsp;<tt>dfs.</tt>{@link
   *     DecimalFormatSymbols#getDecimalSeparator
   *     getDecimalSeparator()}
   *     <dt><i>LocalPositivePrefix&nbsp;&nbsp;</i>
   *         <dd>The string that appears before a positive number (may
   *         be empty), <i>i.e.,</i>&nbsp;<tt>df.</tt>{@link
   *         DecimalFormat#getPositivePrefix
   *         getPositivePrefix()}
   *     <dt><i>LocalPositiveSuffix&nbsp;&nbsp;</i>
   *         <dd>The string that appears after a positive number (may be
   *         empty), <i>i.e.,</i>&nbsp;<tt>df.</tt>{@link
   *         DecimalFormat#getPositiveSuffix
   *         getPositiveSuffix()}
   *     <dt><i>LocalNegativePrefix&nbsp;&nbsp;</i>
   *         <dd>The string that appears before a negative number (may
   *         be empty), <i>i.e.,</i>&nbsp;<tt>df.</tt>{@link
   *         DecimalFormat#getNegativePrefix
   *         getNegativePrefix()}
   *     <dt><i>LocalNegativeSuffix&nbsp;&nbsp;</i>
   *         <dd>The string that appears after a negative number (may be
   *         empty), <i>i.e.,</i>&nbsp;<tt>df.</tt>{@link
   *     DecimalFormat#getNegativeSuffix
   *     getNegativeSuffix()}
   *     <dt><i>LocalNaN&nbsp;&nbsp;</i>
   *         <dd>The string that represents not-a-number for
   *         floating-point values,
   *         <i>i.e.,</i>&nbsp;<tt>dfs.</tt>{@link
   *         DecimalFormatSymbols#getNaN
   *         getNaN()}
   *     <dt><i>LocalInfinity&nbsp;&nbsp;</i>
   *         <dd>The string that represents infinity for floating-point
   *         values, <i>i.e.,</i>&nbsp;<tt>dfs.</tt>{@link
   *         DecimalFormatSymbols#getInfinity
   *         getInfinity()}
   * </dl></blockquote>
   *
   * <h4> <a name="number-syntax">Number syntax</a> </h4>
   *
   * <p> The strings that can be parsed as numbers by an instance of this class
   * are specified in terms of the following regular-expression grammar, where
   * Rmax is the highest digit in the radix being used (for example, Rmax is 9 in base 10).
   *
   * <dl>
   *   <dt><i>NonAsciiDigit</i>:
   *       <dd>A non-ASCII character c for which
   *            {@link Character#isDigit Character.isDigit}<tt>(c)</tt>
   *                        returns&nbsp;true
   *
   *   <dt><i>Non0Digit</i>:
   *       <dd><tt>[1-</tt><i>Rmax</i><tt>] | </tt><i>NonASCIIDigit</i>
   *
   *   <dt><i>Digit</i>:
   *       <dd><tt>[0-</tt><i>Rmax</i><tt>] | </tt><i>NonASCIIDigit</i>
   *
   *   <dt><i>GroupedNumeral</i>:
   *       <dd><tt>(&nbsp;</tt><i>Non0Digit</i>
   *                   <i>Digit</i><tt>?
   *                   </tt><i>Digit</i><tt>?</tt>
   *       <dd>&nbsp;&nbsp;&nbsp;&nbsp;<tt>(&nbsp;</tt><i>LocalGroupSeparator</i>
   *                         <i>Digit</i>
   *                         <i>Digit</i>
   *                         <i>Digit</i><tt> )+ )</tt>
   *
   *   <dt><i>Numeral</i>:
   *       <dd><tt>( ( </tt><i>Digit</i><tt>+ )
   *               | </tt><i>GroupedNumeral</i><tt> )</tt>
   *
   *   <dt><a name="Integer-regex"><i>Integer</i>:</a>
   *       <dd><tt>( [-+]? ( </tt><i>Numeral</i><tt>
   *                               ) )</tt>
   *       <dd><tt>| </tt><i>LocalPositivePrefix</i> <i>Numeral</i>
   *                      <i>LocalPositiveSuffix</i>
   *       <dd><tt>| </tt><i>LocalNegativePrefix</i> <i>Numeral</i>
   *                 <i>LocalNegativeSuffix</i>
   *
   *   <dt><i>DecimalNumeral</i>:
   *       <dd><i>Numeral</i>
   *       <dd><tt>| </tt><i>Numeral</i>
   *                 <i>LocalDecimalSeparator</i>
   *                 <i>Digit</i><tt>*</tt>
   *       <dd><tt>| </tt><i>LocalDecimalSeparator</i>
   *                 <i>Digit</i><tt>+</tt>
   *
   *   <dt><i>Exponent</i>:
   *       <dd><tt>( [eE] [+-]? </tt><i>Digit</i><tt>+ )</tt>
   *
   *   <dt><a name="Decimal-regex"><i>Decimal</i>:</a>
   *       <dd><tt>( [-+]? </tt><i>DecimalNumeral</i>
   *                         <i>Exponent</i><tt>? )</tt>
   *       <dd><tt>| </tt><i>LocalPositivePrefix</i>
   *                 <i>DecimalNumeral</i>
   *                 <i>LocalPositiveSuffix</i>
   *                 <i>Exponent</i><tt>?</tt>
   *       <dd><tt>| </tt><i>LocalNegativePrefix</i>
   *                 <i>DecimalNumeral</i>
   *                 <i>LocalNegativeSuffix</i>
   *                 <i>Exponent</i><tt>?</tt>
   *
   *   <dt><i>HexFloat</i>:
   *       <dd><tt>[-+]? 0[xX][0-9a-fA-F]*\.[0-9a-fA-F]+
   *                 ([pP][-+]?[0-9]+)?</tt>
   *
   *   <dt><i>NonNumber</i>:
   *       <dd><tt>NaN
   *                          | </tt><i>LocalNan</i><tt>
   *                          | Infinity
   *                          | </tt><i>LocalInfinity</i>
   *
   *   <dt><i>SignedNonNumber</i>:
   *       <dd><tt>( [-+]? </tt><i>NonNumber</i><tt> )</tt>
   *       <dd><tt>| </tt><i>LocalPositivePrefix</i>
   *                 <i>NonNumber</i>
   *                 <i>LocalPositiveSuffix</i>
   *       <dd><tt>| </tt><i>LocalNegativePrefix</i>
   *                 <i>NonNumber</i>
   *                 <i>LocalNegativeSuffix</i>
   *
   *   <dt><a name="Float-regex"><i>Float</i></a>:
   *       <dd><i>Decimal</i>
   *           <tt>| </tt><i>HexFloat</i>
   *           <tt>| </tt><i>SignedNonNumber</i>
   *
   * </dl>
   * <p>Whitespace is not significant in the above regular expressions.
   *
   * @since   1.5
   */
  public final class Scanner implements Iterator<String>, Closeable {
  
      // Internal buffer used to hold input
      private CharBuffer buf;
  
      // Size of internal character buffer
      private static final int BUFFER_SIZE = 1024; // change to 1024;
  
      // The index into the buffer currently held by the Scanner
      private int position;
  
      // Internal matcher used for finding delimiters
      private Matcher matcher;
  
      // Pattern used to delimit tokens
      private Pattern delimPattern;
  
      // Pattern found in last hasNext operation
      private Pattern hasNextPattern;
  
      // Position after last hasNext operation
      private int hasNextPosition;
  
      // Result after last hasNext operation
      private String hasNextResult;
  
      // The input source
      private Readable source;
  
      // Boolean is true if source is done
      private boolean sourceClosed = false;
  
      // Boolean indicating more input is required
      private boolean needInput = false;
  
      // Boolean indicating if a delim has been skipped this operation
      private boolean skipped = false;
  
      // A store of a position that the scanner may fall back to
      private int savedScannerPosition = -1;
  
      // A cache of the last primitive type scanned
      private Object typeCache = null;
  
      // Boolean indicating if a match result is available
      private boolean matchValid = false;
  
      // Boolean indicating if this scanner has been closed
      private boolean closed = false;
  
      // The current radix used by this scanner
      private int radix = 10;
  
      // The default radix for this scanner
      private int defaultRadix = 10;
  
      // The locale used by this scanner
      private Locale locale = null;
  
      // A cache of the last few recently used Patterns
      private LRUCache<String,Pattern> patternCache =
      new LRUCache<String,Pattern>(7) {
          protected Pattern create(String s) {
              return Pattern.compile(s);
          }
          protected boolean hasName(Pattern p, String s) {
              return p.pattern().equals(s);
          }
      };
  
      // A holder of the last IOException encountered
      private IOException lastException;
  
      // A pattern for java whitespace
      private static Pattern WHITESPACE_PATTERN = Pattern.compile(
                                                  "\\p{javaWhitespace}+");
  
      // A pattern for any token
      private static Pattern FIND_ANY_PATTERN = Pattern.compile("(?s).*");
  
      // A pattern for non-ASCII digits
      private static Pattern NON_ASCII_DIGIT = Pattern.compile(
          "[\\p{javaDigit}&&[^0-9]]");
  
      // Fields and methods to support scanning primitive types
  
      /**
       * Locale dependent values used to scan numbers
       */
      private String groupSeparator = "\\,";
      private String decimalSeparator = "\\.";
      private String nanString = "NaN";
      private String infinityString = "Infinity";
      private String positivePrefix = "";
      private String negativePrefix = "\\-";
      private String positiveSuffix = "";
      private String negativeSuffix = "";
  
      /**
       * Fields and an accessor method to match booleans
       */
      private static volatile Pattern boolPattern;
      private static final String BOOLEAN_PATTERN = "true|false";
      private static Pattern boolPattern() {
          Pattern bp = boolPattern;
          if (bp == null)
              boolPattern = bp = Pattern.compile(BOOLEAN_PATTERN,
                                            Pattern.CASE_INSENSITIVE);
          return bp;
      }
  
      /**
       * Fields and methods to match bytes, shorts, ints, and longs
       */
      private Pattern integerPattern;
      private String digits = "0123456789abcdefghijklmnopqrstuvwxyz";
      private String non0Digit = "[\\p{javaDigit}&&[^0]]";
      private int SIMPLE_GROUP_INDEX = 5;
      private String buildIntegerPatternString() {
          String radixDigits = digits.substring(0, radix);
          // \\p{javaDigit} is not guaranteed to be appropriate
          // here but what can we do? The final authority will be
          // whatever parse method is invoked, so ultimately the
          // Scanner will do the right thing
          String digit = "((?i)["+radixDigits+"]|\\p{javaDigit})";
          // BEGIN Android-changed: Support non-decimal starting digits.
          // Ie., in addition to 1-9, a-z are also valid radix digits.
          /*
          String groupedNumeral = "("+non0Digit+digit+"?"+digit+"?("+
                                  groupSeparator+digit+digit+digit+")+)";
          */
          String non0RadixDigits = "((?i)[" + digits.substring(1, radix) + "]|(" + non0Digit + "))";
          String groupedNumeral = "("+non0RadixDigits+digit+"?"+digit+"?("+
                                  groupSeparator+digit+digit+digit+")+)";
          // END Android-changed: Support non-decimal starting digits.
          // digit++ is the possessive form which is necessary for reducing
          // backtracking that would otherwise cause unacceptable performance
          String numeral = "(("+ digit+"++)|"+groupedNumeral+")";
          String javaStyleInteger = "([-+]?(" + numeral + "))";
          String negativeInteger = negativePrefix + numeral + negativeSuffix;
          String positiveInteger = positivePrefix + numeral + positiveSuffix;
          return "("+ javaStyleInteger + ")|(" +
              positiveInteger + ")|(" +
              negativeInteger + ")";
      }
      private Pattern integerPattern() {
          if (integerPattern == null) {
              integerPattern = patternCache.forName(buildIntegerPatternString());
          }
          return integerPattern;
      }
  
      /**
       * Fields and an accessor method to match line separators
       */
      private static volatile Pattern separatorPattern;
      private static volatile Pattern linePattern;
      private static final String LINE_SEPARATOR_PATTERN =
                                             "\r\n|[\n\r\u2028\u2029\u0085]";
      private static final String LINE_PATTERN = ".*("+LINE_SEPARATOR_PATTERN+")|.+$";
  
      private static Pattern separatorPattern() {
          Pattern sp = separatorPattern;
          if (sp == null)
              separatorPattern = sp = Pattern.compile(LINE_SEPARATOR_PATTERN);
          return sp;
      }
  
      private static Pattern linePattern() {
          Pattern lp = linePattern;
          if (lp == null)
              linePattern = lp = Pattern.compile(LINE_PATTERN);
          return lp;
      }
  
      /**
       * Fields and methods to match floats and doubles
       */
      private Pattern floatPattern;
      private Pattern decimalPattern;
      private void buildFloatAndDecimalPattern() {
          // \\p{javaDigit} may not be perfect, see above
          String digit = "([0-9]|(\\p{javaDigit}))";
          String exponent = "([eE][+-]?"+digit+"+)?";
          String groupedNumeral = "("+non0Digit+digit+"?"+digit+"?("+
                                  groupSeparator+digit+digit+digit+")+)";
          // Once again digit++ is used for performance, as above
          String numeral = "(("+digit+"++)|"+groupedNumeral+")";
          String decimalNumeral = "("+numeral+"|"+numeral +
              decimalSeparator + digit + "*+|"+ decimalSeparator +
              digit + "++)";
          String nonNumber = "(NaN|"+nanString+"|Infinity|"+
                                 infinityString+")";
          String positiveFloat = "(" + positivePrefix + decimalNumeral +
                              positiveSuffix + exponent + ")";
          String negativeFloat = "(" + negativePrefix + decimalNumeral +
                              negativeSuffix + exponent + ")";
          String decimal = "(([-+]?" + decimalNumeral + exponent + ")|"+
              positiveFloat + "|" + negativeFloat + ")";
          String hexFloat =
              "[-+]?0[xX][0-9a-fA-F]*\\.[0-9a-fA-F]+([pP][-+]?[0-9]+)?";
          String positiveNonNumber = "(" + positivePrefix + nonNumber +
                              positiveSuffix + ")";
          String negativeNonNumber = "(" + negativePrefix + nonNumber +
                              negativeSuffix + ")";
          String signedNonNumber = "(([-+]?"+nonNumber+")|" +
                                   positiveNonNumber + "|" +
                                   negativeNonNumber + ")";
          floatPattern = Pattern.compile(decimal + "|" + hexFloat + "|" +
                                         signedNonNumber);
          decimalPattern = Pattern.compile(decimal);
      }
      private Pattern floatPattern() {
          if (floatPattern == null) {
              buildFloatAndDecimalPattern();
          }
          return floatPattern;
      }
      private Pattern decimalPattern() {
          if (decimalPattern == null) {
              buildFloatAndDecimalPattern();
          }
          return decimalPattern;
      }
  
      // Constructors
  
      /**
       * Constructs a <code>Scanner</code> that returns values scanned
       * from the specified source delimited by the specified pattern.
       *
       * @param source A character source implementing the Readable interface
       * @param pattern A delimiting pattern
       */
      private Scanner(Readable source, Pattern pattern) {
          assert source != null : "source should not be null";
          assert pattern != null : "pattern should not be null";
          this.source = source;
          delimPattern = pattern;
          buf = CharBuffer.allocate(BUFFER_SIZE);
          buf.limit(0);
          matcher = delimPattern.matcher(buf);
          matcher.useTransparentBounds(true);
          matcher.useAnchoringBounds(false);
          useLocale(Locale.getDefault(Locale.Category.FORMAT));
      }
  
      /**
       * Constructs a new <code>Scanner</code> that produces values scanned
       * from the specified source.
       *
       * @param  source A character source implementing the {@link Readable}
       *         interface
       */
      public Scanner(Readable source) {
          this(Objects.requireNonNull(source, "source"), WHITESPACE_PATTERN);
      }
  
      /**
       * Constructs a new <code>Scanner</code> that produces values scanned
       * from the specified input stream. Bytes from the stream are converted
       * into characters using the underlying platform's
       * {@linkplain Charset#defaultCharset() default charset}.
       *
       * @param  source An input stream to be scanned
       */
      public Scanner(InputStream source) {
          this(new InputStreamReader(source), WHITESPACE_PATTERN);
      }
  
      /**
       * Constructs a new <code>Scanner</code> that produces values scanned
       * from the specified input stream. Bytes from the stream are converted
       * into characters using the specified charset.
       *
       * @param  source An input stream to be scanned
       * @param charsetName The encoding type used to convert bytes from the
       *        stream into characters to be scanned
       * @throws IllegalArgumentException if the specified character set
       *         does not exist
       */
      public Scanner(InputStream source, String charsetName) {
          this(makeReadable(Objects.requireNonNull(source, "source"), toCharset(charsetName)),
               WHITESPACE_PATTERN);
      }
  
      /**
       * Returns a charset object for the given charset name.
       * @throws NullPointerException          is csn is null
       * @throws IllegalArgumentException      if the charset is not supported
       */
      private static Charset toCharset(String csn) {
          Objects.requireNonNull(csn, "charsetName");
          try {
              return Charset.forName(csn);
          } catch (IllegalCharsetNameException|UnsupportedCharsetException e) {
              // IllegalArgumentException should be thrown
              throw new IllegalArgumentException(e);
          }
      }
  
      private static Readable makeReadable(InputStream source, Charset charset) {
          return new InputStreamReader(source, charset);
      }
  
      /**
       * Constructs a new <code>Scanner</code> that produces values scanned
       * from the specified file. Bytes from the file are converted into
       * characters using the underlying platform's
       * {@linkplain Charset#defaultCharset() default charset}.
       *
       * @param  source A file to be scanned
       * @throws FileNotFoundException if source is not found
       */
      public Scanner(File source) throws FileNotFoundException {
          this((ReadableByteChannel)(new FileInputStream(source).getChannel()));
      }
  
      /**
       * Constructs a new <code>Scanner</code> that produces values scanned
       * from the specified file. Bytes from the file are converted into
       * characters using the specified charset.
       *
       * @param  source A file to be scanned
       * @param charsetName The encoding type used to convert bytes from the file
       *        into characters to be scanned
       * @throws FileNotFoundException if source is not found
       * @throws IllegalArgumentException if the specified encoding is
       *         not found
       */
      public Scanner(File source, String charsetName)
          throws FileNotFoundException
      {
          this(Objects.requireNonNull(source), toDecoder(charsetName));
      }
  
      private Scanner(File source, CharsetDecoder dec)
          throws FileNotFoundException
      {
          this(makeReadable((ReadableByteChannel)(new FileInputStream(source).getChannel()), dec));
      }
  
      private static CharsetDecoder toDecoder(String charsetName) {
          // Android-changed: Throw an IAE instead of an NPE.
          // Objects.requireNonNull(charsetName, "charsetName");
          if (charsetName == null) {
              throw new IllegalArgumentException("charsetName == null");
          }
          try {
              return Charset.forName(charsetName).newDecoder();
          } catch (IllegalCharsetNameException|UnsupportedCharsetException unused) {
              throw new IllegalArgumentException(charsetName);
          }
      }
  
      private static Readable makeReadable(ReadableByteChannel source,
                                           CharsetDecoder dec) {
          return Channels.newReader(source, dec, -1);
      }
  
      /**
       * Constructs a new <code>Scanner</code> that produces values scanned
       * from the specified file. Bytes from the file are converted into
       * characters using the underlying platform's
       * {@linkplain Charset#defaultCharset() default charset}.
       *
       * @param   source
       *          the path to the file to be scanned
       * @throws  IOException
       *          if an I/O error occurs opening source
       *
       * @since   1.7
       */
      public Scanner(Path source)
          throws IOException
      {
          this(Files.newInputStream(source));
      }
  
      /**
       * Constructs a new <code>Scanner</code> that produces values scanned
       * from the specified file. Bytes from the file are converted into
       * characters using the specified charset.
       *
       * @param   source
       *          the path to the file to be scanned
       * @param   charsetName
       *          The encoding type used to convert bytes from the file
       *          into characters to be scanned
       * @throws  IOException
       *          if an I/O error occurs opening source
       * @throws  IllegalArgumentException
       *          if the specified encoding is not found
       * @since   1.7
       */
      public Scanner(Path source, String charsetName) throws IOException {
          this(Objects.requireNonNull(source), toCharset(charsetName));
      }
  
      private Scanner(Path source, Charset charset)  throws IOException {
          this(makeReadable(Files.newInputStream(source), charset));
      }
  
      /**
       * Constructs a new <code>Scanner</code> that produces values scanned
       * from the specified string.
       *
       * @param  source A string to scan
       */
      public Scanner(String source) {
          this(new StringReader(source), WHITESPACE_PATTERN);
      }
  
      /**
       * Constructs a new <code>Scanner</code> that produces values scanned
       * from the specified channel. Bytes from the source are converted into
       * characters using the underlying platform's
       * {@linkplain Charset#defaultCharset() default charset}.
       *
       * @param  source A channel to scan
       */
      public Scanner(ReadableByteChannel source) {
          this(makeReadable(Objects.requireNonNull(source, "source")),
               WHITESPACE_PATTERN);
      }
  
      private static Readable makeReadable(ReadableByteChannel source) {
          return makeReadable(source, Charset.defaultCharset().newDecoder());
      }
  
      /**
       * Constructs a new <code>Scanner</code> that produces values scanned
       * from the specified channel. Bytes from the source are converted into
       * characters using the specified charset.
       *
       * @param  source A channel to scan
       * @param charsetName The encoding type used to convert bytes from the
       *        channel into characters to be scanned
       * @throws IllegalArgumentException if the specified character set
       *         does not exist
       */
      public Scanner(ReadableByteChannel source, String charsetName) {
          this(makeReadable(Objects.requireNonNull(source, "source"), toDecoder(charsetName)),
               WHITESPACE_PATTERN);
      }
  
      // Private primitives used to support scanning
  
      private void saveState() {
          savedScannerPosition = position;
      }
  
      private void revertState() {
          this.position = savedScannerPosition;
          savedScannerPosition = -1;
          skipped = false;
      }
  
      private boolean revertState(boolean b) {
          this.position = savedScannerPosition;
          savedScannerPosition = -1;
          skipped = false;
          return b;
      }
  
      private void cacheResult() {
          hasNextResult = matcher.group();
          hasNextPosition = matcher.end();
          hasNextPattern = matcher.pattern();
      }
  
      private void cacheResult(String result) {
          hasNextResult = result;
          hasNextPosition = matcher.end();
          hasNextPattern = matcher.pattern();
      }
  
      // Clears both regular cache and type cache
      private void clearCaches() {
          hasNextPattern = null;
          typeCache = null;
      }
  
      // Also clears both the regular cache and the type cache
      private String getCachedResult() {
          position = hasNextPosition;
          hasNextPattern = null;
          typeCache = null;
          return hasNextResult;
      }
  
      // Also clears both the regular cache and the type cache
      private void useTypeCache() {
          if (closed)
              throw new IllegalStateException("Scanner closed");
          position = hasNextPosition;
          hasNextPattern = null;
          typeCache = null;
      }
  
      // Tries to read more input. May block.
      private void readInput() {
          if (buf.limit() == buf.capacity())
              makeSpace();
  
          // Prepare to receive data
          int p = buf.position();
          buf.position(buf.limit());
          buf.limit(buf.capacity());
  
          int n = 0;
          try {
              n = source.read(buf);
          } catch (IOException ioe) {
              lastException = ioe;
              n = -1;
          }
  
          if (n == -1) {
              sourceClosed = true;
              needInput = false;
          }
  
          if (n > 0)
              needInput = false;
  
          // Restore current position and limit for reading
          buf.limit(buf.position());
          buf.position(p);
          // Android-added: reset() the matcher after reading.
          // The matcher implementation eagerly calls toString() so we'll have
          // to update its input whenever the buffer limit, position etc. changes.
          matcher.reset(buf);
      }
  
      // After this method is called there will either be an exception
      // or else there will be space in the buffer
      private boolean makeSpace() {
          clearCaches();
          int offset = savedScannerPosition == -1 ?
              position : savedScannerPosition;
          buf.position(offset);
          // Gain space by compacting buffer
          if (offset > 0) {
              buf.compact();
              translateSavedIndexes(offset);
              position -= offset;
              buf.flip();
              return true;
          }
          // Gain space by growing buffer
          int newSize = buf.capacity() * 2;
          CharBuffer newBuf = CharBuffer.allocate(newSize);
          newBuf.put(buf);
          newBuf.flip();
          translateSavedIndexes(offset);
          position -= offset;
          buf = newBuf;
          matcher.reset(buf);
          return true;
      }
  
      // When a buffer compaction/reallocation occurs the saved indexes must
      // be modified appropriately
      private void translateSavedIndexes(int offset) {
          if (savedScannerPosition != -1)
              savedScannerPosition -= offset;
      }
  
      // If we are at the end of input then NoSuchElement;
      // If there is still input left then InputMismatch
      private void throwFor() {
          skipped = false;
          if ((sourceClosed) && (position == buf.limit()))
              throw new NoSuchElementException();
          else
              throw new InputMismatchException();
      }
  
      // Returns true if a complete token or partial token is in the buffer.
      // It is not necessary to find a complete token since a partial token
      // means that there will be another token with or without more input.
      private boolean hasTokenInBuffer() {
          matchValid = false;
          matcher.usePattern(delimPattern);
          matcher.region(position, buf.limit());
  
          // Skip delims first
          if (matcher.lookingAt())
              position = matcher.end();
  
          // If we are sitting at the end, no more tokens in buffer
          if (position == buf.limit())
              return false;
  
          return true;
      }
  
      /*
       * Returns a "complete token" that matches the specified pattern
       *
       * A token is complete if surrounded by delims; a partial token
       * is prefixed by delims but not postfixed by them
       *
       * The position is advanced to the end of that complete token
       *
       * Pattern == null means accept any token at all
       *
       * Triple return:
       * 1. valid string means it was found
       * 2. null with needInput=false means we won't ever find it
       * 3. null with needInput=true means try again after readInput
       */
      private String getCompleteTokenInBuffer(Pattern pattern) {
          matchValid = false;
  
          // Skip delims first
          matcher.usePattern(delimPattern);
          if (!skipped) { // Enforcing only one skip of leading delims
              matcher.region(position, buf.limit());
              if (matcher.lookingAt()) {
                  // If more input could extend the delimiters then we must wait
                  // for more input
                  if (matcher.hitEnd() && !sourceClosed) {
                      needInput = true;
                      return null;
                  }
                  // The delims were whole and the matcher should skip them
                  skipped = true;
                  position = matcher.end();
              }
          }
  
          // If we are sitting at the end, no more tokens in buffer
          if (position == buf.limit()) {
              if (sourceClosed)
                  return null;
              needInput = true;
              return null;
          }
  
          // Must look for next delims. Simply attempting to match the
          // pattern at this point may find a match but it might not be
          // the first longest match because of missing input, or it might
          // match a partial token instead of the whole thing.
  
          // Then look for next delims
          matcher.region(position, buf.limit());
          boolean foundNextDelim = matcher.find();
          if (foundNextDelim && (matcher.end() == position)) {
              // Zero length delimiter match; we should find the next one
              // using the automatic advance past a zero length match;
              // Otherwise we have just found the same one we just skipped
              foundNextDelim = matcher.find();
          }
          if (foundNextDelim) {
              // In the rare case that more input could cause the match
              // to be lost and there is more input coming we must wait
              // for more input. Note that hitting the end is okay as long
              // as the match cannot go away. It is the beginning of the
              // next delims we want to be sure about, we don't care if
              // they potentially extend further.
              if (matcher.requireEnd() && !sourceClosed) {
                  needInput = true;
                  return null;
              }
              int tokenEnd = matcher.start();
              // There is a complete token.
              if (pattern == null) {
                  // Must continue with match to provide valid MatchResult
                  pattern = FIND_ANY_PATTERN;
              }
              //  Attempt to match against the desired pattern
              matcher.usePattern(pattern);
              matcher.region(position, tokenEnd);
              if (matcher.matches()) {
                  String s = matcher.group();
                  position = matcher.end();
                  return s;
              } else { // Complete token but it does not match
                  return null;
              }
          }
  
          // If we can't find the next delims but no more input is coming,
          // then we can treat the remainder as a whole token
          if (sourceClosed) {
              if (pattern == null) {
                  // Must continue with match to provide valid MatchResult
                  pattern = FIND_ANY_PATTERN;
              }
              // Last token; Match the pattern here or throw
              matcher.usePattern(pattern);
              matcher.region(position, buf.limit());
              if (matcher.matches()) {
                  String s = matcher.group();
                  position = matcher.end();
                  return s;
              }
              // Last piece does not match
              return null;
          }
  
          // There is a partial token in the buffer; must read more
          // to complete it
          needInput = true;
          return null;
      }
  
      // Finds the specified pattern in the buffer up to horizon.
      // Returns a match for the specified input pattern.
      private String findPatternInBuffer(Pattern pattern, int horizon) {
          matchValid = false;
          matcher.usePattern(pattern);
          int bufferLimit = buf.limit();
          int horizonLimit = -1;
          int searchLimit = bufferLimit;
          if (horizon > 0) {
              horizonLimit = position + horizon;
              if (horizonLimit < bufferLimit)
                  searchLimit = horizonLimit;
          }
          matcher.region(position, searchLimit);
          if (matcher.find()) {
              if (matcher.hitEnd() && (!sourceClosed)) {
                  // The match may be longer if didn't hit horizon or real end
                  if (searchLimit != horizonLimit) {
                       // Hit an artificial end; try to extend the match
                      needInput = true;
                      return null;
                  }
                  // The match could go away depending on what is next
                  if ((searchLimit == horizonLimit) && matcher.requireEnd()) {
                      // Rare case: we hit the end of input and it happens
                      // that it is at the horizon and the end of input is
                      // required for the match.
                      needInput = true;
                      return null;
                  }
              }
              // Did not hit end, or hit real end, or hit horizon
              position = matcher.end();
              return matcher.group();
          }
  
          if (sourceClosed)
              return null;
  
          // If there is no specified horizon, or if we have not searched
          // to the specified horizon yet, get more input
          if ((horizon == 0) || (searchLimit != horizonLimit))
              needInput = true;
          return null;
      }
  
      // Returns a match for the specified input pattern anchored at
      // the current position
      private String matchPatternInBuffer(Pattern pattern) {
          matchValid = false;
          matcher.usePattern(pattern);
          matcher.region(position, buf.limit());
          if (matcher.lookingAt()) {
              if (matcher.hitEnd() && (!sourceClosed)) {
                  // Get more input and try again
                  needInput = true;
                  return null;
              }
              position = matcher.end();
              return matcher.group();
          }
  
          if (sourceClosed)
              return null;
  
          // Read more to find pattern
          needInput = true;
          return null;
      }
  
      // Throws if the scanner is closed
      private void ensureOpen() {
          if (closed)
              throw new IllegalStateException("Scanner closed");
      }
  
      // Public methods
  
      /**
       * Closes this scanner.
       *
       * <p> If this scanner has not yet been closed then if its underlying
       * {@linkplain Readable readable} also implements the {@link
       * Closeable} interface then the readable's <tt>close</tt> method
       * will be invoked.  If this scanner is already closed then invoking this
       * method will have no effect.
       *
       * <p>Attempting to perform search operations after a scanner has
       * been closed will result in an {@link IllegalStateException}.
       *
       */
      public void close() {
          if (closed)
              return;
          if (source instanceof Closeable) {
              try {
                  ((Closeable)source).close();
              } catch (IOException ioe) {
                  lastException = ioe;
              }
          }
          sourceClosed = true;
          source = null;
          closed = true;
      }
  
      /**
       * Returns the <code>IOException</code> last thrown by this
       * <code>Scanner</code>'s underlying <code>Readable</code>. This method
       * returns <code>null</code> if no such exception exists.
       *
       * @return the last exception thrown by this scanner's readable
       */
      public IOException ioException() {
          return lastException;
      }
  
      /**
       * Returns the <code>Pattern</code> this <code>Scanner</code> is currently
       * using to match delimiters.
       *
       * @return this scanner's delimiting pattern.
       */
      public Pattern delimiter() {
          return delimPattern;
      }
  
      /**
       * Sets this scanner's delimiting pattern to the specified pattern.
       *
       * @param pattern A delimiting pattern
       * @return this scanner
       */
      public Scanner useDelimiter(Pattern pattern) {
          delimPattern = pattern;
          return this;
      }
  
      /**
       * Sets this scanner's delimiting pattern to a pattern constructed from
       * the specified <code>String</code>.
       *
       * <p> An invocation of this method of the form
       * <tt>useDelimiter(pattern)</tt> behaves in exactly the same way as the
       * invocation <tt>useDelimiter(Pattern.compile(pattern))</tt>.
       *
       * <p> Invoking the {@link #reset} method will set the scanner's delimiter
       * to the <a href= "#default-delimiter">default</a>.
       *
       * @param pattern A string specifying a delimiting pattern
       * @return this scanner
       */
      public Scanner useDelimiter(String pattern) {
          delimPattern = patternCache.forName(pattern);
          return this;
      }
  
      /**
       * Returns this scanner's locale.
       *
       * <p>A scanner's locale affects many elements of its default
       * primitive matching regular expressions; see
       * <a href= "#localized-numbers">localized numbers</a> above.
       *
       * @return this scanner's locale
       */
      public Locale locale() {
          return this.locale;
      }
  
      /**
       * Sets this scanner's locale to the specified locale.
       *
       * <p>A scanner's locale affects many elements of its default
       * primitive matching regular expressions; see
       * <a href= "#localized-numbers">localized numbers</a> above.
       *
       * <p>Invoking the {@link #reset} method will set the scanner's locale to
       * the <a href= "#initial-locale">initial locale</a>.
       *
       * @param locale A string specifying the locale to use
       * @return this scanner
       */
      public Scanner useLocale(Locale locale) {
          if (locale.equals(this.locale))
              return this;
  
          this.locale = locale;
          DecimalFormat df =
              (DecimalFormat)NumberFormat.getNumberInstance(locale);
          DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(locale);
  
          // These must be literalized to avoid collision with regex
          // metacharacters such as dot or parenthesis
          groupSeparator =   "\\" + dfs.getGroupingSeparator();
          decimalSeparator = "\\" + dfs.getDecimalSeparator();
  
          // Quoting the nonzero length locale-specific things
          // to avoid potential conflict with metacharacters
          nanString = "\\Q" + dfs.getNaN() + "\\E";
          infinityString = "\\Q" + dfs.getInfinity() + "\\E";
          positivePrefix = df.getPositivePrefix();
          if (positivePrefix.length() > 0)
              positivePrefix = "\\Q" + positivePrefix + "\\E";
          negativePrefix = df.getNegativePrefix();
          if (negativePrefix.length() > 0)
              negativePrefix = "\\Q" + negativePrefix + "\\E";
          positiveSuffix = df.getPositiveSuffix();
          if (positiveSuffix.length() > 0)
              positiveSuffix = "\\Q" + positiveSuffix + "\\E";
          negativeSuffix = df.getNegativeSuffix();
          if (negativeSuffix.length() > 0)
              negativeSuffix = "\\Q" + negativeSuffix + "\\E";
  
          // Force rebuilding and recompilation of locale dependent
          // primitive patterns
          integerPattern = null;
          floatPattern = null;
  
          return this;
      }
  
      /**
       * Returns this scanner's default radix.
       *
       * <p>A scanner's radix affects elements of its default
       * number matching regular expressions; see
       * <a href= "#localized-numbers">localized numbers</a> above.
       *
       * @return the default radix of this scanner
       */
      public int radix() {
          return this.defaultRadix;
      }
  
      /**
       * Sets this scanner's default radix to the specified radix.
       *
       * <p>A scanner's radix affects elements of its default
       * number matching regular expressions; see
       * <a href= "#localized-numbers">localized numbers</a> above.
       *
       * <p>If the radix is less than <code>Character.MIN_RADIX</code>
       * or greater than <code>Character.MAX_RADIX</code>, then an
       * <code>IllegalArgumentException</code> is thrown.
       *
       * <p>Invoking the {@link #reset} method will set the scanner's radix to
       * <code>10</code>.
       *
       * @param radix The radix to use when scanning numbers
       * @return this scanner
       * @throws IllegalArgumentException if radix is out of range
       */
      public Scanner useRadix(int radix) {
          if ((radix < Character.MIN_RADIX) || (radix > Character.MAX_RADIX))
              throw new IllegalArgumentException("radix:"+radix);
  
          if (this.defaultRadix == radix)
              return this;
          this.defaultRadix = radix;
          // Force rebuilding and recompilation of radix dependent patterns
          integerPattern = null;
          return this;
      }
  
      // The next operation should occur in the specified radix but
      // the default is left untouched.
      private void setRadix(int radix) {
          // BEGIN Android-added: Complain loudly if a bogus radix is being set.
          if (radix > Character.MAX_RADIX) {
              throw new IllegalArgumentException("radix == " + radix);
          }
          // END Android-added: Complain loudly if a bogus radix is being set.
  
          if (this.radix != radix) {
              // Force rebuilding and recompilation of radix dependent patterns
              integerPattern = null;
              this.radix = radix;
          }
      }
  
      /**
       * Returns the match result of the last scanning operation performed
       * by this scanner. This method throws <code>IllegalStateException</code>
       * if no match has been performed, or if the last match was
       * not successful.
       *
       * <p>The various <code>next</code>methods of <code>Scanner</code>
       * make a match result available if they complete without throwing an
       * exception. For instance, after an invocation of the {@link #nextInt}
       * method that returned an int, this method returns a
       * <code>MatchResult</code> for the search of the
       * <a href="#Integer-regex"><i>Integer</i></a> regular expression
       * defined above. Similarly the {@link #findInLine},
       * {@link #findWithinHorizon}, and {@link #skip} methods will make a
       * match available if they succeed.
       *
       * @return a match result for the last match operation
       * @throws IllegalStateException  If no match result is available
       */
      public MatchResult match() {
          if (!matchValid)
              throw new IllegalStateException("No match result available");
          return matcher.toMatchResult();
      }
  
      /**
       * <p>Returns the string representation of this <code>Scanner</code>. The
       * string representation of a <code>Scanner</code> contains information
       * that may be useful for debugging. The exact format is unspecified.
       *
       * @return  The string representation of this scanner
       */
      public String toString() {
          StringBuilder sb = new StringBuilder();
          sb.append("java.util.Scanner");
          sb.append("[delimiters=" + delimPattern + "]");
          sb.append("[position=" + position + "]");
          sb.append("[match valid=" + matchValid + "]");
          sb.append("[need input=" + needInput + "]");
          sb.append("[source closed=" + sourceClosed + "]");
          sb.append("[skipped=" + skipped + "]");
          sb.append("[group separator=" + groupSeparator + "]");
          sb.append("[decimal separator=" + decimalSeparator + "]");
          sb.append("[positive prefix=" + positivePrefix + "]");
          sb.append("[negative prefix=" + negativePrefix + "]");
          sb.append("[positive suffix=" + positiveSuffix + "]");
          sb.append("[negative suffix=" + negativeSuffix + "]");
          sb.append("[NaN string=" + nanString + "]");
          sb.append("[infinity string=" + infinityString + "]");
          return sb.toString();
      }
  
      /**
       * Returns true if this scanner has another token in its input.
       * This method may block while waiting for input to scan.
       * The scanner does not advance past any input.
       *
       * @return true if and only if this scanner has another token
       * @throws IllegalStateException if this scanner is closed
       * @see Iterator
       */
      public boolean hasNext() {
          ensureOpen();
          saveState();
          while (!sourceClosed) {
              if (hasTokenInBuffer())
                  return revertState(true);
              readInput();
          }
          boolean result = hasTokenInBuffer();
          return revertState(result);
      }
  
      /**
       * Finds and returns the next complete token from this scanner.
       * A complete token is preceded and followed by input that matches
       * the delimiter pattern. This method may block while waiting for input
       * to scan, even if a previous invocation of {@link #hasNext} returned
       * <code>true</code>.
       *
       * @return the next token
       * @throws NoSuchElementException if no more tokens are available
       * @throws IllegalStateException if this scanner is closed
       * @see Iterator
       */
      public String next() {
          ensureOpen();
          clearCaches();
  
          while (true) {
              String token = getCompleteTokenInBuffer(null);
              if (token != null) {
                  matchValid = true;
                  skipped = false;
                  return token;
              }
              if (needInput)
                  readInput();
              else
                  throwFor();
          }
      }
  
      /**
       * The remove operation is not supported by this implementation of
       * <code>Iterator</code>.
       *
       * @throws UnsupportedOperationException if this method is invoked.
       * @see Iterator
       */
      public void remove() {
          throw new UnsupportedOperationException();
      }
  
      /**
       * Returns true if the next token matches the pattern constructed from the
       * specified string. The scanner does not advance past any input.
       *
       * <p> An invocation of this method of the form <tt>hasNext(pattern)</tt>
       * behaves in exactly the same way as the invocation
       * <tt>hasNext(Pattern.compile(pattern))</tt>.
       *
       * @param pattern a string specifying the pattern to scan
       * @return true if and only if this scanner has another token matching
       *         the specified pattern
       * @throws IllegalStateException if this scanner is closed
       */
      public boolean hasNext(String pattern)  {
          return hasNext(patternCache.forName(pattern));
      }
  
      /**
       * Returns the next token if it matches the pattern constructed from the
       * specified string.  If the match is successful, the scanner advances
       * past the input that matched the pattern.
       *
       * <p> An invocation of this method of the form <tt>next(pattern)</tt>
       * behaves in exactly the same way as the invocation
       * <tt>next(Pattern.compile(pattern))</tt>.
       *
       * @param pattern a string specifying the pattern to scan
       * @return the next token
       * @throws NoSuchElementException if no such tokens are available
       * @throws IllegalStateException if this scanner is closed
       */
      public String next(String pattern)  {
          return next(patternCache.forName(pattern));
      }
  
      /**
       * Returns true if the next complete token matches the specified pattern.
       * A complete token is prefixed and postfixed by input that matches
       * the delimiter pattern. This method may block while waiting for input.
       * The scanner does not advance past any input.
       *
       * @param pattern the pattern to scan for
       * @return true if and only if this scanner has another token matching
       *         the specified pattern
       * @throws IllegalStateException if this scanner is closed
       */
      public boolean hasNext(Pattern pattern) {
          ensureOpen();
          if (pattern == null)
              throw new NullPointerException();
          hasNextPattern = null;
          saveState();
  
          while (true) {
              if (getCompleteTokenInBuffer(pattern) != null) {
                  matchValid = true;
                  cacheResult();
                  return revertState(true);
              }
              if (needInput)
                  readInput();
              else
                  return revertState(false);
          }
      }
  
      /**
       * Returns the next token if it matches the specified pattern. This
       * method may block while waiting for input to scan, even if a previous
       * invocation of {@link #hasNext(Pattern)} returned <code>true</code>.
       * If the match is successful, the scanner advances past the input that
       * matched the pattern.
       *
       * @param pattern the pattern to scan for
       * @return the next token
       * @throws NoSuchElementException if no more tokens are available
       * @throws IllegalStateException if this scanner is closed
       */
      public String next(Pattern pattern) {
          ensureOpen();
          if (pattern == null)
              throw new NullPointerException();
  
          // Did we already find this pattern?
          if (hasNextPattern == pattern)
              return getCachedResult();
          clearCaches();
  
          // Search for the pattern
          while (true) {
              String token = getCompleteTokenInBuffer(pattern);
              if (token != null) {
                  matchValid = true;
                  skipped = false;
                  return token;
              }
              if (needInput)
                  readInput();
              else
                  throwFor();
          }
      }
  
      /**
       * Returns true if there is another line in the input of this scanner.
       * This method may block while waiting for input. The scanner does not
       * advance past any input.
       *
       * @return true if and only if this scanner has another line of input
       * @throws IllegalStateException if this scanner is closed
       */
      public boolean hasNextLine() {
          saveState();
  
          String result = findWithinHorizon(linePattern(), 0);
          if (result != null) {
              MatchResult mr = this.match();
              String lineSep = mr.group(1);
              if (lineSep != null) {
                  result = result.substring(0, result.length() -
                                            lineSep.length());
                  cacheResult(result);
  
              } else {
                  cacheResult();
              }
          }
          revertState();
          return (result != null);
      }
  
      /**
       * Advances this scanner past the current line and returns the input
       * that was skipped.
       *
       * This method returns the rest of the current line, excluding any line
       * separator at the end. The position is set to the beginning of the next
       * line.
       *
       * <p>Since this method continues to search through the input looking
       * for a line separator, it may buffer all of the input searching for
       * the line to skip if no line separators are present.
       *
       * @return the line that was skipped
       * @throws NoSuchElementException if no line was found
       * @throws IllegalStateException if this scanner is closed
       */
      public String nextLine() {
          if (hasNextPattern == linePattern())
              return getCachedResult();
          clearCaches();
  
          String result = findWithinHorizon(linePattern, 0);
          if (result == null)
              throw new NoSuchElementException("No line found");
          MatchResult mr = this.match();
          String lineSep = mr.group(1);
          if (lineSep != null)
              result = result.substring(0, result.length() - lineSep.length());
          if (result == null)
              throw new NoSuchElementException();
          else
              return result;
      }
  
      // Public methods that ignore delimiters
  
      /**
       * Attempts to find the next occurrence of a pattern constructed from the
       * specified string, ignoring delimiters.
       *
       * <p>An invocation of this method of the form <tt>findInLine(pattern)</tt>
       * behaves in exactly the same way as the invocation
       * <tt>findInLine(Pattern.compile(pattern))</tt>.
       *
       * @param pattern a string specifying the pattern to search for
       * @return the text that matched the specified pattern
       * @throws IllegalStateException if this scanner is closed
       */
      public String findInLine(String pattern) {
          return findInLine(patternCache.forName(pattern));
      }
  
      /**
       * Attempts to find the next occurrence of the specified pattern ignoring
       * delimiters. If the pattern is found before the next line separator, the
       * scanner advances past the input that matched and returns the string that
       * matched the pattern.
       * If no such pattern is detected in the input up to the next line
       * separator, then <code>null</code> is returned and the scanner's
       * position is unchanged. This method may block waiting for input that
       * matches the pattern.
       *
       * <p>Since this method continues to search through the input looking
       * for the specified pattern, it may buffer all of the input searching for
       * the desired token if no line separators are present.
       *
       * @param pattern the pattern to scan for
       * @return the text that matched the specified pattern
       * @throws IllegalStateException if this scanner is closed
       */
      public String findInLine(Pattern pattern) {
          ensureOpen();
          if (pattern == null)
              throw new NullPointerException();
          clearCaches();
          // Expand buffer to include the next newline or end of input
          int endPosition = 0;
          saveState();
          while (true) {
              String token = findPatternInBuffer(separatorPattern(), 0);
              if (token != null) {
                  endPosition = matcher.start();
                  break; // up to next newline
              }
              if (needInput) {
                  readInput();
              } else {
                  endPosition = buf.limit();
                  break; // up to end of input
              }
          }
          revertState();
          int horizonForLine = endPosition - position;
          // If there is nothing between the current pos and the next
          // newline simply return null, invoking findWithinHorizon
          // with "horizon=0" will scan beyond the line bound.
          if (horizonForLine == 0)
              return null;
          // Search for the pattern
          return findWithinHorizon(pattern, horizonForLine);
      }
  
      /**
       * Attempts to find the next occurrence of a pattern constructed from the
       * specified string, ignoring delimiters.
       *
       * <p>An invocation of this method of the form
       * <tt>findWithinHorizon(pattern)</tt> behaves in exactly the same way as
       * the invocation
       * <tt>findWithinHorizon(Pattern.compile(pattern, horizon))</tt>.
       *
       * @param pattern a string specifying the pattern to search for
       * @param horizon the search horizon
       * @return the text that matched the specified pattern
       * @throws IllegalStateException if this scanner is closed
       * @throws IllegalArgumentException if horizon is negative
       */
      public String findWithinHorizon(String pattern, int horizon) {
          return findWithinHorizon(patternCache.forName(pattern), horizon);
      }
  
      /**
       * Attempts to find the next occurrence of the specified pattern.
       *
       * <p>This method searches through the input up to the specified
       * search horizon, ignoring delimiters. If the pattern is found the
       * scanner advances past the input that matched and returns the string
       * that matched the pattern. If no such pattern is detected then the
       * null is returned and the scanner's position remains unchanged. This
       * method may block waiting for input that matches the pattern.
       *
       * <p>A scanner will never search more than <code>horizon</code> code
       * points beyond its current position. Note that a match may be clipped
       * by the horizon; that is, an arbitrary match result may have been
       * different if the horizon had been larger. The scanner treats the
       * horizon as a transparent, non-anchoring bound (see {@link
       * Matcher#useTransparentBounds} and {@link Matcher#useAnchoringBounds}).
       *
       * <p>If horizon is <code>0</code>, then the horizon is ignored and
       * this method continues to search through the input looking for the
       * specified pattern without bound. In this case it may buffer all of
       * the input searching for the pattern.
       *
       * <p>If horizon is negative, then an IllegalArgumentException is
       * thrown.
       *
       * @param pattern the pattern to scan for
       * @param horizon the search horizon
       * @return the text that matched the specified pattern
       * @throws IllegalStateException if this scanner is closed
       * @throws IllegalArgumentException if horizon is negative
       */
      public String findWithinHorizon(Pattern pattern, int horizon) {
          ensureOpen();
          if (pattern == null)
              throw new NullPointerException();
          if (horizon < 0)
              throw new IllegalArgumentException("horizon < 0");
          clearCaches();
  
          // Search for the pattern
          while (true) {
              String token = findPatternInBuffer(pattern, horizon);
              if (token != null) {
                  matchValid = true;
                  return token;
              }
              if (needInput)
                  readInput();
              else
                  break; // up to end of input
          }
          return null;
      }
  
      /**
       * Skips input that matches the specified pattern, ignoring delimiters.
       * This method will skip input if an anchored match of the specified
       * pattern succeeds.
       *
       * <p>If a match to the specified pattern is not found at the
       * current position, then no input is skipped and a
       * <tt>NoSuchElementException</tt> is thrown.
       *
       * <p>Since this method seeks to match the specified pattern starting at
       * the scanner's current position, patterns that can match a lot of
       * input (".*", for example) may cause the scanner to buffer a large
       * amount of input.
       *
       * <p>Note that it is possible to skip something without risking a
       * <code>NoSuchElementException</code> by using a pattern that can
       * match nothing, e.g., <code>sc.skip("[ \t]*")</code>.
       *
       * @param pattern a string specifying the pattern to skip over
       * @return this scanner
       * @throws NoSuchElementException if the specified pattern is not found
       * @throws IllegalStateException if this scanner is closed
       */
      public Scanner skip(Pattern pattern) {
          ensureOpen();
          if (pattern == null)
              throw new NullPointerException();
          clearCaches();
  
          // Search for the pattern
          while (true) {
              String token = matchPatternInBuffer(pattern);
              if (token != null) {
                  matchValid = true;
                  position = matcher.end();
                  return this;
              }
              if (needInput)
                  readInput();
              else
                  throw new NoSuchElementException();
          }
      }
  
      /**
       * Skips input that matches a pattern constructed from the specified
       * string.
       *
       * <p> An invocation of this method of the form <tt>skip(pattern)</tt>
       * behaves in exactly the same way as the invocation
       * <tt>skip(Pattern.compile(pattern))</tt>.
       *
       * @param pattern a string specifying the pattern to skip over
       * @return this scanner
       * @throws IllegalStateException if this scanner is closed
       */
      public Scanner skip(String pattern) {
          return skip(patternCache.forName(pattern));
      }
  
      // Convenience methods for scanning primitives
  
      /**
       * Returns true if the next token in this scanner's input can be
       * interpreted as a boolean value using a case insensitive pattern
       * created from the string "true|false".  The scanner does not
       * advance past the input that matched.
       *
       * @return true if and only if this scanner's next token is a valid
       *         boolean value
       * @throws IllegalStateException if this scanner is closed
       */
      public boolean hasNextBoolean()  {
          return hasNext(boolPattern());
      }
  
      /**
       * Scans the next token of the input into a boolean value and returns
       * that value. This method will throw <code>InputMismatchException</code>
       * if the next token cannot be translated into a valid boolean value.
       * If the match is successful, the scanner advances past the input that
       * matched.
       *
       * @return the boolean scanned from the input
       * @throws InputMismatchException if the next token is not a valid boolean
       * @throws NoSuchElementException if input is exhausted
       * @throws IllegalStateException if this scanner is closed
       */
      public boolean nextBoolean()  {
          clearCaches();
          return Boolean.parseBoolean(next(boolPattern()));
      }
  
      /**
       * Returns true if the next token in this scanner's input can be
       * interpreted as a byte value in the default radix using the
       * {@link #nextByte} method. The scanner does not advance past any input.
       *
       * @return true if and only if this scanner's next token is a valid
       *         byte value
       * @throws IllegalStateException if this scanner is closed
       */
      public boolean hasNextByte() {
          return hasNextByte(defaultRadix);
      }
  
      /**
       * Returns true if the next token in this scanner's input can be
       * interpreted as a byte value in the specified radix using the
       * {@link #nextByte} method. The scanner does not advance past any input.
       *
       * @param radix the radix used to interpret the token as a byte value
       * @return true if and only if this scanner's next token is a valid
       *         byte value
       * @throws IllegalStateException if this scanner is closed
       */
      public boolean hasNextByte(int radix) {
          setRadix(radix);
          boolean result = hasNext(integerPattern());
          if (result) { // Cache it
              try {
                  String s = (matcher.group(SIMPLE_GROUP_INDEX) == null) ?
                      processIntegerToken(hasNextResult) :
                      hasNextResult;
                  typeCache = Byte.parseByte(s, radix);
              } catch (NumberFormatException nfe) {
                  result = false;
              }
          }
          return result;
      }
  
      /**
       * Scans the next token of the input as a <tt>byte</tt>.
       *
       * <p> An invocation of this method of the form
       * <tt>nextByte()</tt> behaves in exactly the same way as the
       * invocation <tt>nextByte(radix)</tt>, where <code>radix</code>
       * is the default radix of this scanner.
       *
       * @return the <tt>byte</tt> scanned from the input
       * @throws InputMismatchException
       *         if the next token does not match the <i>Integer</i>
       *         regular expression, or is out of range
       * @throws NoSuchElementException if input is exhausted
       * @throws IllegalStateException if this scanner is closed
       */
      public byte nextByte() {
           return nextByte(defaultRadix);
      }
  
      /**
       * Scans the next token of the input as a <tt>byte</tt>.
       * This method will throw <code>InputMismatchException</code>
       * if the next token cannot be translated into a valid byte value as
       * described below. If the translation is successful, the scanner advances
       * past the input that matched.
       *
       * <p> If the next token matches the <a
       * href="#Integer-regex"><i>Integer</i></a> regular expression defined
       * above then the token is converted into a <tt>byte</tt> value as if by
       * removing all locale specific prefixes, group separators, and locale
       * specific suffixes, then mapping non-ASCII digits into ASCII
       * digits via {@link Character#digit Character.digit}, prepending a
       * negative sign (-) if the locale specific negative prefixes and suffixes
       * were present, and passing the resulting string to
       * {@link Byte#parseByte(String, int) Byte.parseByte} with the
       * specified radix.
       *
       * @param radix the radix used to interpret the token as a byte value
       * @return the <tt>byte</tt> scanned from the input
       * @throws InputMismatchException
       *         if the next token does not match the <i>Integer</i>
       *         regular expression, or is out of range
       * @throws NoSuchElementException if input is exhausted
       * @throws IllegalStateException if this scanner is closed
       */
      public byte nextByte(int radix) {
          // Check cached result
          if ((typeCache != null) && (typeCache instanceof Byte)
              && this.radix == radix) {
              byte val = ((Byte)typeCache).byteValue();
              useTypeCache();
              return val;
          }
          setRadix(radix);
          clearCaches();
          // Search for next byte
          try {
              String s = next(integerPattern());
              if (matcher.group(SIMPLE_GROUP_INDEX) == null)
                  s = processIntegerToken(s);
              return Byte.parseByte(s, radix);
          } catch (NumberFormatException nfe) {
              position = matcher.start(); // don't skip bad token
              throw new InputMismatchException(nfe.getMessage());
          }
      }
  
      /**
       * Returns true if the next token in this scanner's input can be
       * interpreted as a short value in the default radix using the
       * {@link #nextShort} method. The scanner does not advance past any input.
       *
       * @return true if and only if this scanner's next token is a valid
       *         short value in the default radix
       * @throws IllegalStateException if this scanner is closed
       */
      public boolean hasNextShort() {
          return hasNextShort(defaultRadix);
      }
  
      /**
       * Returns true if the next token in this scanner's input can be
       * interpreted as a short value in the specified radix using the
       * {@link #nextShort} method. The scanner does not advance past any input.
       *
       * @param radix the radix used to interpret the token as a short value
       * @return true if and only if this scanner's next token is a valid
       *         short value in the specified radix
       * @throws IllegalStateException if this scanner is closed
       */
      public boolean hasNextShort(int radix) {
          setRadix(radix);
          boolean result = hasNext(integerPattern());
          if (result) { // Cache it
              try {
                  String s = (matcher.group(SIMPLE_GROUP_INDEX) == null) ?
                      processIntegerToken(hasNextResult) :
                      hasNextResult;
                  typeCache = Short.parseShort(s, radix);
              } catch (NumberFormatException nfe) {
                  result = false;
              }
          }
          return result;
      }
  
      /**
       * Scans the next token of the input as a <tt>short</tt>.
       *
       * <p> An invocation of this method of the form
       * <tt>nextShort()</tt> behaves in exactly the same way as the
       * invocation <tt>nextShort(radix)</tt>, where <code>radix</code>
       * is the default radix of this scanner.
       *
       * @return the <tt>short</tt> scanned from the input
       * @throws InputMismatchException
       *         if the next token does not match the <i>Integer</i>
       *         regular expression, or is out of range
       * @throws NoSuchElementException if input is exhausted
       * @throws IllegalStateException if this scanner is closed
       */
      public short nextShort() {
          return nextShort(defaultRadix);
      }
  
      /**
       * Scans the next token of the input as a <tt>short</tt>.
       * This method will throw <code>InputMismatchException</code>
       * if the next token cannot be translated into a valid short value as
       * described below. If the translation is successful, the scanner advances
       * past the input that matched.
       *
       * <p> If the next token matches the <a
       * href="#Integer-regex"><i>Integer</i></a> regular expression defined
       * above then the token is converted into a <tt>short</tt> value as if by
       * removing all locale specific prefixes, group separators, and locale
       * specific suffixes, then mapping non-ASCII digits into ASCII
       * digits via {@link Character#digit Character.digit}, prepending a
       * negative sign (-) if the locale specific negative prefixes and suffixes
       * were present, and passing the resulting string to
       * {@link Short#parseShort(String, int) Short.parseShort} with the
       * specified radix.
       *
       * @param radix the radix used to interpret the token as a short value
       * @return the <tt>short</tt> scanned from the input
       * @throws InputMismatchException
       *         if the next token does not match the <i>Integer</i>
       *         regular expression, or is out of range
       * @throws NoSuchElementException if input is exhausted
       * @throws IllegalStateException if this scanner is closed
       */
      public short nextShort(int radix) {
          // Check cached result
          if ((typeCache != null) && (typeCache instanceof Short)
              && this.radix == radix) {
              short val = ((Short)typeCache).shortValue();
              useTypeCache();
              return val;
          }
          setRadix(radix);
          clearCaches();
          // Search for next short
          try {
              String s = next(integerPattern());
              if (matcher.group(SIMPLE_GROUP_INDEX) == null)
                  s = processIntegerToken(s);
              return Short.parseShort(s, radix);
          } catch (NumberFormatException nfe) {
              position = matcher.start(); // don't skip bad token
              throw new InputMismatchException(nfe.getMessage());
          }
      }
  
      /**
       * Returns true if the next token in this scanner's input can be
       * interpreted as an int value in the default radix using the
       * {@link #nextInt} method. The scanner does not advance past any input.
       *
       * @return true if and only if this scanner's next token is a valid
       *         int value
       * @throws IllegalStateException if this scanner is closed
       */
      public boolean hasNextInt() {
          return hasNextInt(defaultRadix);
      }
  
      /**
       * Returns true if the next token in this scanner's input can be
       * interpreted as an int value in the specified radix using the
       * {@link #nextInt} method. The scanner does not advance past any input.
       *
       * @param radix the radix used to interpret the token as an int value
       * @return true if and only if this scanner's next token is a valid
       *         int value
       * @throws IllegalStateException if this scanner is closed
       */
      public boolean hasNextInt(int radix) {
          setRadix(radix);
          boolean result = hasNext(integerPattern());
          if (result) { // Cache it
              try {
                  String s = (matcher.group(SIMPLE_GROUP_INDEX) == null) ?
                      processIntegerToken(hasNextResult) :
                      hasNextResult;
                  typeCache = Integer.parseInt(s, radix);
              } catch (NumberFormatException nfe) {
                  result = false;
              }
          }
          return result;
      }
  
      /**
       * The integer token must be stripped of prefixes, group separators,
       * and suffixes, non ascii digits must be converted into ascii digits
       * before parse will accept it.
       */
      private String processIntegerToken(String token) {
          String result = token.replaceAll(""+groupSeparator, "");
          boolean isNegative = false;
          int preLen = negativePrefix.length();
          if ((preLen > 0) && result.startsWith(negativePrefix)) {
              isNegative = true;
              result = result.substring(preLen);
          }
          int sufLen = negativeSuffix.length();
          if ((sufLen > 0) && result.endsWith(negativeSuffix)) {
              isNegative = true;
              result = result.substring(result.length() - sufLen,
                                        result.length());
          }
          if (isNegative)
              result = "-" + result;
          return result;
      }
  
      /**
       * Scans the next token of the input as an <tt>int</tt>.
       *
       * <p> An invocation of this method of the form
       * <tt>nextInt()</tt> behaves in exactly the same way as the
       * invocation <tt>nextInt(radix)</tt>, where <code>radix</code>
       * is the default radix of this scanner.
       *
       * @return the <tt>int</tt> scanned from the input
       * @throws InputMismatchException
       *         if the next token does not match the <i>Integer</i>
       *         regular expression, or is out of range
       * @throws NoSuchElementException if input is exhausted
       * @throws IllegalStateException if this scanner is closed
       */
      public int nextInt() {
          return nextInt(defaultRadix);
      }
  
      /**
       * Scans the next token of the input as an <tt>int</tt>.
       * This method will throw <code>InputMismatchException</code>
       * if the next token cannot be translated into a valid int value as
       * described below. If the translation is successful, the scanner advances
       * past the input that matched.
       *
       * <p> If the next token matches the <a
       * href="#Integer-regex"><i>Integer</i></a> regular expression defined
       * above then the token is converted into an <tt>int</tt> value as if by
       * removing all locale specific prefixes, group separators, and locale
       * specific suffixes, then mapping non-ASCII digits into ASCII
       * digits via {@link Character#digit Character.digit}, prepending a
       * negative sign (-) if the locale specific negative prefixes and suffixes
       * were present, and passing the resulting string to
       * {@link Integer#parseInt(String, int) Integer.parseInt} with the
       * specified radix.
       *
       * @param radix the radix used to interpret the token as an int value
       * @return the <tt>int</tt> scanned from the input
       * @throws InputMismatchException
       *         if the next token does not match the <i>Integer</i>
       *         regular expression, or is out of range
       * @throws NoSuchElementException if input is exhausted
       * @throws IllegalStateException if this scanner is closed
       */
      public int nextInt(int radix) {
          // Check cached result
          if ((typeCache != null) && (typeCache instanceof Integer)
              && this.radix == radix) {
              int val = ((Integer)typeCache).intValue();
              useTypeCache();
              return val;
          }
          setRadix(radix);
          clearCaches();
          // Search for next int
          try {
              String s = next(integerPattern());
              if (matcher.group(SIMPLE_GROUP_INDEX) == null)
                  s = processIntegerToken(s);
              return Integer.parseInt(s, radix);
          } catch (NumberFormatException nfe) {
              position = matcher.start(); // don't skip bad token
              throw new InputMismatchException(nfe.getMessage());
          }
      }
  
      /**
       * Returns true if the next token in this scanner's input can be
       * interpreted as a long value in the default radix using the
       * {@link #nextLong} method. The scanner does not advance past any input.
       *
       * @return true if and only if this scanner's next token is a valid
       *         long value
       * @throws IllegalStateException if this scanner is closed
       */
      public boolean hasNextLong() {
          return hasNextLong(defaultRadix);
      }
  
      /**
       * Returns true if the next token in this scanner's input can be
       * interpreted as a long value in the specified radix using the
       * {@link #nextLong} method. The scanner does not advance past any input.
       *
       * @param radix the radix used to interpret the token as a long value
       * @return true if and only if this scanner's next token is a valid
       *         long value
       * @throws IllegalStateException if this scanner is closed
       */
      public boolean hasNextLong(int radix) {
          setRadix(radix);
          boolean result = hasNext(integerPattern());
          if (result) { // Cache it
              try {
                  String s = (matcher.group(SIMPLE_GROUP_INDEX) == null) ?
                      processIntegerToken(hasNextResult) :
                      hasNextResult;
                  typeCache = Long.parseLong(s, radix);
              } catch (NumberFormatException nfe) {
                  result = false;
              }
          }
          return result;
      }
  
      /**
       * Scans the next token of the input as a <tt>long</tt>.
       *
       * <p> An invocation of this method of the form
       * <tt>nextLong()</tt> behaves in exactly the same way as the
       * invocation <tt>nextLong(radix)</tt>, where <code>radix</code>
       * is the default radix of this scanner.
       *
       * @return the <tt>long</tt> scanned from the input
       * @throws InputMismatchException
       *         if the next token does not match the <i>Integer</i>
       *         regular expression, or is out of range
       * @throws NoSuchElementException if input is exhausted
       * @throws IllegalStateException if this scanner is closed
       */
      public long nextLong() {
          return nextLong(defaultRadix);
      }
  
      /**
       * Scans the next token of the input as a <tt>long</tt>.
       * This method will throw <code>InputMismatchException</code>
       * if the next token cannot be translated into a valid long value as
       * described below. If the translation is successful, the scanner advances
       * past the input that matched.
       *
       * <p> If the next token matches the <a
       * href="#Integer-regex"><i>Integer</i></a> regular expression defined
       * above then the token is converted into a <tt>long</tt> value as if by
       * removing all locale specific prefixes, group separators, and locale
       * specific suffixes, then mapping non-ASCII digits into ASCII
       * digits via {@link Character#digit Character.digit}, prepending a
       * negative sign (-) if the locale specific negative prefixes and suffixes
       * were present, and passing the resulting string to
       * {@link Long#parseLong(String, int) Long.parseLong} with the
       * specified radix.
       *
       * @param radix the radix used to interpret the token as an int value
       * @return the <tt>long</tt> scanned from the input
       * @throws InputMismatchException
       *         if the next token does not match the <i>Integer</i>
       *         regular expression, or is out of range
       * @throws NoSuchElementException if input is exhausted
       * @throws IllegalStateException if this scanner is closed
       */
      public long nextLong(int radix) {
          // Check cached result
          if ((typeCache != null) && (typeCache instanceof Long)
              && this.radix == radix) {
              long val = ((Long)typeCache).longValue();
              useTypeCache();
              return val;
          }
          setRadix(radix);
          clearCaches();
          try {
              String s = next(integerPattern());
              if (matcher.group(SIMPLE_GROUP_INDEX) == null)
                  s = processIntegerToken(s);
              return Long.parseLong(s, radix);
          } catch (NumberFormatException nfe) {
              position = matcher.start(); // don't skip bad token
              throw new InputMismatchException(nfe.getMessage());
          }
      }
  
      /**
       * The float token must be stripped of prefixes, group separators,
       * and suffixes, non ascii digits must be converted into ascii digits
       * before parseFloat will accept it.
       *
       * If there are non-ascii digits in the token these digits must
       * be processed before the token is passed to parseFloat.
       */
      private String processFloatToken(String token) {
          String result = token.replaceAll(groupSeparator, "");
          if (!decimalSeparator.equals("\\."))
              result = result.replaceAll(decimalSeparator, ".");
          boolean isNegative = false;
          int preLen = negativePrefix.length();
          if ((preLen > 0) && result.startsWith(negativePrefix)) {
              isNegative = true;
              result = result.substring(preLen);
          }
          int sufLen = negativeSuffix.length();
          if ((sufLen > 0) && result.endsWith(negativeSuffix)) {
              isNegative = true;
              result = result.substring(result.length() - sufLen,
                                        result.length());
          }
          if (result.equals(nanString))
              result = "NaN";
          if (result.equals(infinityString))
              result = "Infinity";
          // BEGIN Android-added: Match the infinity symbol.
          if (result.equals("\u221E"))
              result = "Infinity";
          // END Android-added: Match the infinity symbol.
          if (isNegative)
              result = "-" + result;
  
          // Translate non-ASCII digits
          Matcher m = NON_ASCII_DIGIT.matcher(result);
          if (m.find()) {
              StringBuilder inASCII = new StringBuilder();
              for (int i=0; i<result.length(); i++) {
                  char nextChar = result.charAt(i);
                  if (Character.isDigit(nextChar)) {
                      int d = Character.digit(nextChar, 10);
                      if (d != -1)
                          inASCII.append(d);
                      else
                          inASCII.append(nextChar);
                  } else {
                      inASCII.append(nextChar);
                  }
              }
              result = inASCII.toString();
          }
  
          return result;
      }
  
      /**
       * Returns true if the next token in this scanner's input can be
       * interpreted as a float value using the {@link #nextFloat}
       * method. The scanner does not advance past any input.
       *
       * @return true if and only if this scanner's next token is a valid
       *         float value
       * @throws IllegalStateException if this scanner is closed
       */
      public boolean hasNextFloat() {
          setRadix(10);
          boolean result = hasNext(floatPattern());
          if (result) { // Cache it
              try {
                  String s = processFloatToken(hasNextResult);
                  typeCache = Float.valueOf(Float.parseFloat(s));
              } catch (NumberFormatException nfe) {
                  result = false;
              }
          }
          return result;
      }
  
      /**
       * Scans the next token of the input as a <tt>float</tt>.
       * This method will throw <code>InputMismatchException</code>
       * if the next token cannot be translated into a valid float value as
       * described below. If the translation is successful, the scanner advances
       * past the input that matched.
       *
       * <p> If the next token matches the <a
       * href="#Float-regex"><i>Float</i></a> regular expression defined above
       * then the token is converted into a <tt>float</tt> value as if by
       * removing all locale specific prefixes, group separators, and locale
       * specific suffixes, then mapping non-ASCII digits into ASCII
       * digits via {@link Character#digit Character.digit}, prepending a
       * negative sign (-) if the locale specific negative prefixes and suffixes
       * were present, and passing the resulting string to
       * {@link Float#parseFloat Float.parseFloat}. If the token matches
       * the localized NaN or infinity strings, then either "Nan" or "Infinity"
       * is passed to {@link Float#parseFloat(String) Float.parseFloat} as
       * appropriate.
       *
       * @return the <tt>float</tt> scanned from the input
       * @throws InputMismatchException
       *         if the next token does not match the <i>Float</i>
       *         regular expression, or is out of range
       * @throws NoSuchElementException if input is exhausted
       * @throws IllegalStateException if this scanner is closed
       */
      public float nextFloat() {
          // Check cached result
          if ((typeCache != null) && (typeCache instanceof Float)) {
              float val = ((Float)typeCache).floatValue();
              useTypeCache();
              return val;
          }
          setRadix(10);
          clearCaches();
          try {
              return Float.parseFloat(processFloatToken(next(floatPattern())));
          } catch (NumberFormatException nfe) {
              position = matcher.start(); // don't skip bad token
              throw new InputMismatchException(nfe.getMessage());
          }
      }
  
      /**
       * Returns true if the next token in this scanner's input can be
       * interpreted as a double value using the {@link #nextDouble}
       * method. The scanner does not advance past any input.
       *
       * @return true if and only if this scanner's next token is a valid
       *         double value
       * @throws IllegalStateException if this scanner is closed
       */
      public boolean hasNextDouble() {
          setRadix(10);
          boolean result = hasNext(floatPattern());
          if (result) { // Cache it
              try {
                  String s = processFloatToken(hasNextResult);
                  typeCache = Double.valueOf(Double.parseDouble(s));
              } catch (NumberFormatException nfe) {
                  result = false;
              }
          }
          return result;
      }
  
      /**
       * Scans the next token of the input as a <tt>double</tt>.
       * This method will throw <code>InputMismatchException</code>
       * if the next token cannot be translated into a valid double value.
       * If the translation is successful, the scanner advances past the input
       * that matched.
       *
       * <p> If the next token matches the <a
       * href="#Float-regex"><i>Float</i></a> regular expression defined above
       * then the token is converted into a <tt>double</tt> value as if by
       * removing all locale specific prefixes, group separators, and locale
       * specific suffixes, then mapping non-ASCII digits into ASCII
       * digits via {@link Character#digit Character.digit}, prepending a
       * negative sign (-) if the locale specific negative prefixes and suffixes
       * were present, and passing the resulting string to
       * {@link Double#parseDouble Double.parseDouble}. If the token matches
       * the localized NaN or infinity strings, then either "Nan" or "Infinity"
       * is passed to {@link Double#parseDouble(String) Double.parseDouble} as
       * appropriate.
       *
       * @return the <tt>double</tt> scanned from the input
       * @throws InputMismatchException
       *         if the next token does not match the <i>Float</i>
       *         regular expression, or is out of range
       * @throws NoSuchElementException if the input is exhausted
       * @throws IllegalStateException if this scanner is closed
       */
      public double nextDouble() {
          // Check cached result
          if ((typeCache != null) && (typeCache instanceof Double)) {
              double val = ((Double)typeCache).doubleValue();
              useTypeCache();
              return val;
          }
          setRadix(10);
          clearCaches();
          // Search for next float
          try {
              return Double.parseDouble(processFloatToken(next(floatPattern())));
          } catch (NumberFormatException nfe) {
              position = matcher.start(); // don't skip bad token
              throw new InputMismatchException(nfe.getMessage());
          }
      }
  
      // Convenience methods for scanning multi precision numbers
  
      /**
       * Returns true if the next token in this scanner's input can be
       * interpreted as a <code>BigInteger</code> in the default radix using the
       * {@link #nextBigInteger} method. The scanner does not advance past any
       * input.
       *
       * @return true if and only if this scanner's next token is a valid
       *         <code>BigInteger</code>
       * @throws IllegalStateException if this scanner is closed
       */
      public boolean hasNextBigInteger() {
          return hasNextBigInteger(defaultRadix);
      }
  
      /**
       * Returns true if the next token in this scanner's input can be
       * interpreted as a <code>BigInteger</code> in the specified radix using
       * the {@link #nextBigInteger} method. The scanner does not advance past
       * any input.
       *
       * @param radix the radix used to interpret the token as an integer
       * @return true if and only if this scanner's next token is a valid
       *         <code>BigInteger</code>
       * @throws IllegalStateException if this scanner is closed
       */
      public boolean hasNextBigInteger(int radix) {
          setRadix(radix);
          boolean result = hasNext(integerPattern());
          if (result) { // Cache it
              try {
                  String s = (matcher.group(SIMPLE_GROUP_INDEX) == null) ?
                      processIntegerToken(hasNextResult) :
                      hasNextResult;
                  typeCache = new BigInteger(s, radix);
              } catch (NumberFormatException nfe) {
                  result = false;
              }
          }
          return result;
      }
  
      /**
       * Scans the next token of the input as a {@link BigInteger
       * BigInteger}.
       *
       * <p> An invocation of this method of the form
       * <tt>nextBigInteger()</tt> behaves in exactly the same way as the
       * invocation <tt>nextBigInteger(radix)</tt>, where <code>radix</code>
       * is the default radix of this scanner.
       *
       * @return the <tt>BigInteger</tt> scanned from the input
       * @throws InputMismatchException
       *         if the next token does not match the <i>Integer</i>
       *         regular expression, or is out of range
       * @throws NoSuchElementException if the input is exhausted
       * @throws IllegalStateException if this scanner is closed
       */
      public BigInteger nextBigInteger() {
          return nextBigInteger(defaultRadix);
      }
  
      /**
       * Scans the next token of the input as a {@link BigInteger
       * BigInteger}.
       *
       * <p> If the next token matches the <a
       * href="#Integer-regex"><i>Integer</i></a> regular expression defined
       * above then the token is converted into a <tt>BigInteger</tt> value as if
       * by removing all group separators, mapping non-ASCII digits into ASCII
       * digits via the {@link Character#digit Character.digit}, and passing the
       * resulting string to the {@link
       * BigInteger#BigInteger(String)
       * BigInteger(String, int)} constructor with the specified radix.
       *
       * @param radix the radix used to interpret the token
       * @return the <tt>BigInteger</tt> scanned from the input
       * @throws InputMismatchException
       *         if the next token does not match the <i>Integer</i>
       *         regular expression, or is out of range
       * @throws NoSuchElementException if the input is exhausted
       * @throws IllegalStateException if this scanner is closed
       */
      public BigInteger nextBigInteger(int radix) {
          // Check cached result
          if ((typeCache != null) && (typeCache instanceof BigInteger)
              && this.radix == radix) {
              BigInteger val = (BigInteger)typeCache;
              useTypeCache();
              return val;
          }
          setRadix(radix);
          clearCaches();
          // Search for next int
          try {
              String s = next(integerPattern());
              if (matcher.group(SIMPLE_GROUP_INDEX) == null)
                  s = processIntegerToken(s);
              return new BigInteger(s, radix);
          } catch (NumberFormatException nfe) {
              position = matcher.start(); // don't skip bad token
              throw new InputMismatchException(nfe.getMessage());
          }
      }
  
      /**
       * Returns true if the next token in this scanner's input can be
       * interpreted as a <code>BigDecimal</code> using the
       * {@link #nextBigDecimal} method. The scanner does not advance past any
       * input.
       *
       * @return true if and only if this scanner's next token is a valid
       *         <code>BigDecimal</code>
       * @throws IllegalStateException if this scanner is closed
       */
      public boolean hasNextBigDecimal() {
          setRadix(10);
          boolean result = hasNext(decimalPattern());
          if (result) { // Cache it
              try {
                  String s = processFloatToken(hasNextResult);
                  typeCache = new BigDecimal(s);
              } catch (NumberFormatException nfe) {
                  result = false;
              }
          }
          return result;
      }
  
      /**
       * Scans the next token of the input as a {@link BigDecimal
       * BigDecimal}.
       *
       * <p> If the next token matches the <a
       * href="#Decimal-regex"><i>Decimal</i></a> regular expression defined
       * above then the token is converted into a <tt>BigDecimal</tt> value as if
       * by removing all group separators, mapping non-ASCII digits into ASCII
       * digits via the {@link Character#digit Character.digit}, and passing the
       * resulting string to the {@link
       * BigDecimal#BigDecimal(String) BigDecimal(String)}
       * constructor.
       *
       * @return the <tt>BigDecimal</tt> scanned from the input
       * @throws InputMismatchException
       *         if the next token does not match the <i>Decimal</i>
       *         regular expression, or is out of range
       * @throws NoSuchElementException if the input is exhausted
       * @throws IllegalStateException if this scanner is closed
       */
      public BigDecimal nextBigDecimal() {
          // Check cached result
          if ((typeCache != null) && (typeCache instanceof BigDecimal)) {
              BigDecimal val = (BigDecimal)typeCache;
              useTypeCache();
              return val;
          }
          setRadix(10);
          clearCaches();
          // Search for next float
          try {
              String s = processFloatToken(next(decimalPattern()));
              return new BigDecimal(s);
          } catch (NumberFormatException nfe) {
              position = matcher.start(); // don't skip bad token
              throw new InputMismatchException(nfe.getMessage());
          }
      }
  
      /**
       * Resets this scanner.
       *
       * <p> Resetting a scanner discards all of its explicit state
       * information which may have been changed by invocations of {@link
       * #useDelimiter}, {@link #useLocale}, or {@link #useRadix}.
       *
       * <p> An invocation of this method of the form
       * <tt>scanner.reset()</tt> behaves in exactly the same way as the
       * invocation
       *
       * <blockquote><pre>{@code
       *   scanner.useDelimiter("\\p{javaWhitespace}+")
       *          .useLocale(Locale.getDefault(Locale.Category.FORMAT))
       *          .useRadix(10);
       * }</pre></blockquote>
       *
       * @return this scanner
       *
       * @since 1.6
       */
      public Scanner reset() {
          delimPattern = WHITESPACE_PATTERN;
          useLocale(Locale.getDefault(Locale.Category.FORMAT));
          useRadix(10);
          clearCaches();
          return this;
      }
  }
  