• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This code is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License version 2 only, as
8  * published by the Free Software Foundation.  Oracle designates this
9  * particular file as subject to the "Classpath" exception as provided
10  * by Oracle in the LICENSE file that accompanied this code.
11  *
12  * This code is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15  * version 2 for more details (a copy is included in the LICENSE file that
16  * accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License version
19  * 2 along with this work; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21  *
22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23  * or visit www.oracle.com if you need additional information or have any
24  * questions.
25  */
26 
27 package java.util;
28 
29 import java.io.*;
30 import java.math.*;
31 import java.nio.*;
32 import java.nio.channels.*;
33 import java.nio.charset.*;
34 import java.nio.file.Path;
35 import java.nio.file.Files;
36 import java.text.*;
37 import java.util.function.Consumer;
38 import java.util.regex.*;
39 import java.util.stream.Stream;
40 import java.util.stream.StreamSupport;
41 
42 /**
43  * A simple text scanner which can parse primitive types and strings using
44  * regular expressions.
45  *
46  * <p>A {@code Scanner} breaks its input into tokens using a
47  * delimiter pattern, which by default matches whitespace. The resulting
48  * tokens may then be converted into values of different types using the
49  * various {@code next} methods.
50  *
51  * <p>For example, this code allows a user to read a number from
52  * {@code System.in}:
53  * <blockquote><pre>{@code
54  *     Scanner sc = new Scanner(System.in);
55  *     int i = sc.nextInt();
56  * }</pre></blockquote>
57  *
58  * <p>As another example, this code allows {@code long} types to be
59  * assigned from entries in a file {@code myNumbers}:
60  * <blockquote><pre>{@code
61  *      Scanner sc = new Scanner(new File("myNumbers"));
62  *      while (sc.hasNextLong()) {
63  *          long aLong = sc.nextLong();
64  *      }
65  * }</pre></blockquote>
66  *
67  * <p>The scanner can also use delimiters other than whitespace. This
68  * example reads several items in from a string:
69  * <blockquote><pre>{@code
70  *     String input = "1 fish 2 fish red fish blue fish";
71  *     Scanner s = new Scanner(input).useDelimiter("\\s*fish\\s*");
72  *     System.out.println(s.nextInt());
73  *     System.out.println(s.nextInt());
74  *     System.out.println(s.next());
75  *     System.out.println(s.next());
76  *     s.close();
77  * }</pre></blockquote>
78  * <p>
79  * prints the following output:
80  * <blockquote><pre>{@code
81  *     1
82  *     2
83  *     red
84  *     blue
85  * }</pre></blockquote>
86  *
87  * <p>The same output can be generated with this code, which uses a regular
88  * expression to parse all four tokens at once:
89  * <blockquote><pre>{@code
90  *     String input = "1 fish 2 fish red fish blue fish";
91  *     Scanner s = new Scanner(input);
92  *     s.findInLine("(\\d+) fish (\\d+) fish (\\w+) fish (\\w+)");
93  *     MatchResult result = s.match();
94  *     for (int i=1; i<=result.groupCount(); i++)
95  *         System.out.println(result.group(i));
96  *     s.close();
97  * }</pre></blockquote>
98  *
99  * <p>The <a id="default-delimiter">default whitespace delimiter</a> used
100  * by a scanner is as recognized by {@link Character#isWhitespace(char)
101  * Character.isWhitespace()}. The {@link #reset reset()}
102  * method will reset the value of the scanner's delimiter to the default
103  * whitespace delimiter regardless of whether it was previously changed.
104  *
105  * <p>A scanning operation may block waiting for input.
106  *
107  * <p>The {@link #next} and {@link #hasNext} methods and their
108  * companion methods (such as {@link #nextInt} and
109  * {@link #hasNextInt}) first skip any input that matches the delimiter
110  * pattern, and then attempt to return the next token. Both {@code hasNext()}
111  * and {@code next()} methods may block waiting for further input.  Whether a
112  * {@code hasNext()} method blocks has no connection to whether or not its
113  * associated {@code next()} method will block. The {@link #tokens} method
114  * may also block waiting for input.
115  *
116  * <p>The {@link #findInLine findInLine()},
117  * {@link #findWithinHorizon findWithinHorizon()},
118  * {@link #skip skip()}, and {@link #findAll findAll()}
119  * methods operate independently of the delimiter pattern. These methods will
120  * attempt to match the specified pattern with no regard to delimiters in the
121  * input and thus can be used in special circumstances where delimiters are
122  * not relevant. These methods may block waiting for more input.
123  *
124  * <p>When a scanner throws an {@link InputMismatchException}, the scanner
125  * will not pass the token that caused the exception, so that it may be
126  * retrieved or skipped via some other method.
127  *
128  * <p>Depending upon the type of delimiting pattern, empty tokens may be
129  * returned. For example, the pattern {@code "\\s+"} will return no empty
130  * tokens since it matches multiple instances of the delimiter. The delimiting
131  * pattern {@code "\\s"} could return empty tokens since it only passes one
132  * space at a time.
133  *
134  * <p> A scanner can read text from any object which implements the {@link
135  * java.lang.Readable} interface.  If an invocation of the underlying
136  * readable's {@link java.lang.Readable#read read()} method throws an {@link
137  * java.io.IOException} then the scanner assumes that the end of the input
138  * has been reached.  The most recent {@code IOException} thrown by the
139  * underlying readable can be retrieved via the {@link #ioException} method.
140  *
141  * <p>When a {@code Scanner} is closed, it will close its input source
142  * if the source implements the {@link java.io.Closeable} interface.
143  *
144  * <p>A {@code Scanner} is not safe for multithreaded use without
145  * external synchronization.
146  *
147  * <p>Unless otherwise mentioned, passing a {@code null} parameter into
148  * any method of a {@code Scanner} will cause a
149  * {@code NullPointerException} to be thrown.
150  *
151  * <p>A scanner will default to interpreting numbers as decimal unless a
152  * different radix has been set by using the {@link #useRadix} method. The
153  * {@link #reset} method will reset the value of the scanner's radix to
154  * {@code 10} regardless of whether it was previously changed.
155  *
156  * <h2> <a id="localized-numbers">Localized numbers</a> </h2>
157  *
158  * <p> An instance of this class is capable of scanning numbers in the standard
159  * formats as well as in the formats of the scanner's locale. A scanner's
160  * <a id="initial-locale">initial locale </a>is the value returned by the {@link
161  * java.util.Locale#getDefault(Locale.Category)
162  * Locale.getDefault(Locale.Category.FORMAT)} method; it may be changed via the {@link
163  * #useLocale useLocale()} method. The {@link #reset} method will reset the value of the
164  * scanner's locale to the initial locale regardless of whether it was
165  * previously changed.
166  *
167  * <p>The localized formats are defined in terms of the following parameters,
168  * which for a particular locale are taken from that locale's {@link
169  * java.text.DecimalFormat DecimalFormat} object, {@code df}, and its and
170  * {@link java.text.DecimalFormatSymbols DecimalFormatSymbols} object,
171  * {@code dfs}.
172  *
173  * <blockquote><dl>
174  *     <dt><i>LocalGroupSeparator&nbsp;&nbsp;</i>
175  *         <dd>The character used to separate thousands groups,
176  *         <i>i.e.,</i>&nbsp;{@code dfs.}{@link
177  *         java.text.DecimalFormatSymbols#getGroupingSeparator
178  *         getGroupingSeparator()}
179  *     <dt><i>LocalDecimalSeparator&nbsp;&nbsp;</i>
180  *         <dd>The character used for the decimal point,
181  *     <i>i.e.,</i>&nbsp;{@code dfs.}{@link
182  *     java.text.DecimalFormatSymbols#getDecimalSeparator
183  *     getDecimalSeparator()}
184  *     <dt><i>LocalPositivePrefix&nbsp;&nbsp;</i>
185  *         <dd>The string that appears before a positive number (may
186  *         be empty), <i>i.e.,</i>&nbsp;{@code df.}{@link
187  *         java.text.DecimalFormat#getPositivePrefix
188  *         getPositivePrefix()}
189  *     <dt><i>LocalPositiveSuffix&nbsp;&nbsp;</i>
190  *         <dd>The string that appears after a positive number (may be
191  *         empty), <i>i.e.,</i>&nbsp;{@code df.}{@link
192  *         java.text.DecimalFormat#getPositiveSuffix
193  *         getPositiveSuffix()}
194  *     <dt><i>LocalNegativePrefix&nbsp;&nbsp;</i>
195  *         <dd>The string that appears before a negative number (may
196  *         be empty), <i>i.e.,</i>&nbsp;{@code df.}{@link
197  *         java.text.DecimalFormat#getNegativePrefix
198  *         getNegativePrefix()}
199  *     <dt><i>LocalNegativeSuffix&nbsp;&nbsp;</i>
200  *         <dd>The string that appears after a negative number (may be
201  *         empty), <i>i.e.,</i>&nbsp;{@code df.}{@link
202  *     java.text.DecimalFormat#getNegativeSuffix
203  *     getNegativeSuffix()}
204  *     <dt><i>LocalNaN&nbsp;&nbsp;</i>
205  *         <dd>The string that represents not-a-number for
206  *         floating-point values,
207  *         <i>i.e.,</i>&nbsp;{@code dfs.}{@link
208  *         java.text.DecimalFormatSymbols#getNaN
209  *         getNaN()}
210  *     <dt><i>LocalInfinity&nbsp;&nbsp;</i>
211  *         <dd>The string that represents infinity for floating-point
212  *         values, <i>i.e.,</i>&nbsp;{@code dfs.}{@link
213  *         java.text.DecimalFormatSymbols#getInfinity
214  *         getInfinity()}
215  * </dl></blockquote>
216  *
217  * <h3> <a id="number-syntax">Number syntax</a> </h3>
218  *
219  * <p> The strings that can be parsed as numbers by an instance of this class
220  * are specified in terms of the following regular-expression grammar, where
221  * Rmax is the highest digit in the radix being used (for example, Rmax is 9 in base 10).
222  *
223  * <dl>
224  *   <dt><i>NonAsciiDigit</i>:
225  *       <dd>A non-ASCII character c for which
226  *            {@link java.lang.Character#isDigit Character.isDigit}{@code (c)}
227  *                        returns&nbsp;true
228  *
229  *   <dt><i>Non0Digit</i>:
230  *       <dd>{@code [1-}<i>Rmax</i>{@code ] | }<i>NonASCIIDigit</i>
231  *
232  *   <dt><i>Digit</i>:
233  *       <dd>{@code [0-}<i>Rmax</i>{@code ] | }<i>NonASCIIDigit</i>
234  *
235  *   <dt><i>GroupedNumeral</i>:
236  *       <dd><code>(&nbsp;</code><i>Non0Digit</i>
237  *                   <i>Digit</i>{@code ?
238  *                   }<i>Digit</i>{@code ?}
239  *       <dd>&nbsp;&nbsp;&nbsp;&nbsp;<code>(&nbsp;</code><i>LocalGroupSeparator</i>
240  *                         <i>Digit</i>
241  *                         <i>Digit</i>
242  *                         <i>Digit</i>{@code  )+ )}
243  *
244  *   <dt><i>Numeral</i>:
245  *       <dd>{@code ( ( }<i>Digit</i>{@code + )
246  *               | }<i>GroupedNumeral</i>{@code  )}
247  *
248  *   <dt><a id="Integer-regex"><i>Integer</i>:</a>
249  *       <dd>{@code ( [-+]? ( }<i>Numeral</i>{@code
250  *                               ) )}
251  *       <dd>{@code | }<i>LocalPositivePrefix</i> <i>Numeral</i>
252  *                      <i>LocalPositiveSuffix</i>
253  *       <dd>{@code | }<i>LocalNegativePrefix</i> <i>Numeral</i>
254  *                 <i>LocalNegativeSuffix</i>
255  *
256  *   <dt><i>DecimalNumeral</i>:
257  *       <dd><i>Numeral</i>
258  *       <dd>{@code | }<i>Numeral</i>
259  *                 <i>LocalDecimalSeparator</i>
260  *                 <i>Digit</i>{@code *}
261  *       <dd>{@code | }<i>LocalDecimalSeparator</i>
262  *                 <i>Digit</i>{@code +}
263  *
264  *   <dt><i>Exponent</i>:
265  *       <dd>{@code ( [eE] [+-]? }<i>Digit</i>{@code + )}
266  *
267  *   <dt><a id="Decimal-regex"><i>Decimal</i>:</a>
268  *       <dd>{@code ( [-+]? }<i>DecimalNumeral</i>
269  *                         <i>Exponent</i>{@code ? )}
270  *       <dd>{@code | }<i>LocalPositivePrefix</i>
271  *                 <i>DecimalNumeral</i>
272  *                 <i>LocalPositiveSuffix</i>
273  *                 <i>Exponent</i>{@code ?}
274  *       <dd>{@code | }<i>LocalNegativePrefix</i>
275  *                 <i>DecimalNumeral</i>
276  *                 <i>LocalNegativeSuffix</i>
277  *                 <i>Exponent</i>{@code ?}
278  *
279  *   <dt><i>HexFloat</i>:
280  *       <dd>{@code [-+]? 0[xX][0-9a-fA-F]*\.[0-9a-fA-F]+
281  *                 ([pP][-+]?[0-9]+)?}
282  *
283  *   <dt><i>NonNumber</i>:
284  *       <dd>{@code NaN
285  *                          | }<i>LocalNan</i>{@code
286  *                          | Infinity
287  *                          | }<i>LocalInfinity</i>
288  *
289  *   <dt><i>SignedNonNumber</i>:
290  *       <dd>{@code ( [-+]? }<i>NonNumber</i>{@code  )}
291  *       <dd>{@code | }<i>LocalPositivePrefix</i>
292  *                 <i>NonNumber</i>
293  *                 <i>LocalPositiveSuffix</i>
294  *       <dd>{@code | }<i>LocalNegativePrefix</i>
295  *                 <i>NonNumber</i>
296  *                 <i>LocalNegativeSuffix</i>
297  *
298  *   <dt><a id="Float-regex"><i>Float</i></a>:
299  *       <dd><i>Decimal</i>
300  *           {@code | }<i>HexFloat</i>
301  *           {@code | }<i>SignedNonNumber</i>
302  *
303  * </dl>
304  * <p>Whitespace is not significant in the above regular expressions.
305  *
306  * @since   1.5
307  */
308 public final class Scanner implements Iterator<String>, Closeable {
309 
310     // Internal buffer used to hold input
311     private CharBuffer buf;
312 
313     // Size of internal character buffer
314     private static final int BUFFER_SIZE = 1024; // change to 1024;
315 
316     // The index into the buffer currently held by the Scanner
317     private int position;
318 
319     // Internal matcher used for finding delimiters
320     private Matcher matcher;
321 
322     // Pattern used to delimit tokens
323     private Pattern delimPattern;
324 
325     // Pattern found in last hasNext operation
326     private Pattern hasNextPattern;
327 
328     // Position after last hasNext operation
329     private int hasNextPosition;
330 
331     // Result after last hasNext operation
332     private String hasNextResult;
333 
334     // The input source
335     private Readable source;
336 
337     // Boolean is true if source is done
338     private boolean sourceClosed = false;
339 
340     // Boolean indicating more input is required
341     private boolean needInput = false;
342 
343     // Boolean indicating if a delim has been skipped this operation
344     private boolean skipped = false;
345 
346     // A store of a position that the scanner may fall back to
347     private int savedScannerPosition = -1;
348 
349     // A cache of the last primitive type scanned
350     private Object typeCache = null;
351 
352     // Boolean indicating if a match result is available
353     private boolean matchValid = false;
354 
355     // Boolean indicating if this scanner has been closed
356     private boolean closed = false;
357 
358     // The current radix used by this scanner
359     private int radix = 10;
360 
361     // The default radix for this scanner
362     private int defaultRadix = 10;
363 
364     // The locale used by this scanner
365     private Locale locale = null;
366 
367     // A cache of the last few recently used Patterns
368     private PatternLRUCache patternCache = new PatternLRUCache(7);
369 
370     // A holder of the last IOException encountered
371     private IOException lastException;
372 
373     // Number of times this scanner's state has been modified.
374     // Generally incremented on most public APIs and checked
375     // within spliterator implementations.
376     int modCount;
377 
378     // A pattern for java whitespace
379     private static Pattern WHITESPACE_PATTERN = Pattern.compile(
380                                                 "\\p{javaWhitespace}+");
381 
382     // A pattern for any token
383     private static Pattern FIND_ANY_PATTERN = Pattern.compile("(?s).*");
384 
385     // A pattern for non-ASCII digits
386     private static Pattern NON_ASCII_DIGIT = Pattern.compile(
387         "[\\p{javaDigit}&&[^0-9]]");
388 
389     // Fields and methods to support scanning primitive types
390 
391     /**
392      * Locale dependent values used to scan numbers
393      */
394     private String groupSeparator = "\\,";
395     private String decimalSeparator = "\\.";
396     private String nanString = "NaN";
397     private String infinityString = "Infinity";
398     private String positivePrefix = "";
399     private String negativePrefix = "\\-";
400     private String positiveSuffix = "";
401     private String negativeSuffix = "";
402 
403     /**
404      * Fields and an accessor method to match booleans
405      */
406     private static volatile Pattern boolPattern;
407     private static final String BOOLEAN_PATTERN = "true|false";
boolPattern()408     private static Pattern boolPattern() {
409         Pattern bp = boolPattern;
410         if (bp == null)
411             boolPattern = bp = Pattern.compile(BOOLEAN_PATTERN,
412                                           Pattern.CASE_INSENSITIVE);
413         return bp;
414     }
415 
416     /**
417      * Fields and methods to match bytes, shorts, ints, and longs
418      */
419     private Pattern integerPattern;
420     private String digits = "0123456789abcdefghijklmnopqrstuvwxyz";
421     private String non0Digit = "[\\p{javaDigit}&&[^0]]";
422     private int SIMPLE_GROUP_INDEX = 5;
buildIntegerPatternString()423     private String buildIntegerPatternString() {
424         String radixDigits = digits.substring(0, radix);
425         // \\p{javaDigit} is not guaranteed to be appropriate
426         // here but what can we do? The final authority will be
427         // whatever parse method is invoked, so ultimately the
428         // Scanner will do the right thing
429         String digit = "((?i)["+radixDigits+"\\p{javaDigit}])";
430         // BEGIN Android-changed: Support non-decimal starting digits.
431         // Ie., in addition to 1-9, a-z are also valid radix digits.
432         /*
433         String groupedNumeral = "("+non0Digit+digit+"?"+digit+"?("+
434                                 groupSeparator+digit+digit+digit+")+)";
435         */
436         String non0RadixDigits = "((?i)[" + digits.substring(1, radix) + "]|(" + non0Digit + "))";
437         String groupedNumeral = "("+non0RadixDigits+digit+"?"+digit+"?("+
438                                 groupSeparator+digit+digit+digit+")+)";
439         // END Android-changed: Support non-decimal starting digits.
440         // digit++ is the possessive form which is necessary for reducing
441         // backtracking that would otherwise cause unacceptable performance
442         String numeral = "(("+ digit+"++)|"+groupedNumeral+")";
443         String javaStyleInteger = "([-+]?(" + numeral + "))";
444         String negativeInteger = negativePrefix + numeral + negativeSuffix;
445         String positiveInteger = positivePrefix + numeral + positiveSuffix;
446         return "("+ javaStyleInteger + ")|(" +
447             positiveInteger + ")|(" +
448             negativeInteger + ")";
449     }
integerPattern()450     private Pattern integerPattern() {
451         if (integerPattern == null) {
452             integerPattern = patternCache.forName(buildIntegerPatternString());
453         }
454         return integerPattern;
455     }
456 
457     /**
458      * Fields and an accessor method to match line separators
459      */
460     private static volatile Pattern separatorPattern;
461     private static volatile Pattern linePattern;
462     private static final String LINE_SEPARATOR_PATTERN =
463                                            "\r\n|[\n\r\u2028\u2029\u0085]";
464     private static final String LINE_PATTERN = ".*("+LINE_SEPARATOR_PATTERN+")|.+$";
465 
separatorPattern()466     private static Pattern separatorPattern() {
467         Pattern sp = separatorPattern;
468         if (sp == null)
469             separatorPattern = sp = Pattern.compile(LINE_SEPARATOR_PATTERN);
470         return sp;
471     }
472 
linePattern()473     private static Pattern linePattern() {
474         Pattern lp = linePattern;
475         if (lp == null)
476             linePattern = lp = Pattern.compile(LINE_PATTERN);
477         return lp;
478     }
479 
480     /**
481      * Fields and methods to match floats and doubles
482      */
483     private Pattern floatPattern;
484     private Pattern decimalPattern;
buildFloatAndDecimalPattern()485     private void buildFloatAndDecimalPattern() {
486         // \\p{javaDigit} may not be perfect, see above
487         String digit = "(([0-9\\p{javaDigit}]))";
488         String exponent = "([eE][+-]?"+digit+"+)?";
489         String groupedNumeral = "("+non0Digit+digit+"?"+digit+"?("+
490                                 groupSeparator+digit+digit+digit+")+)";
491         // Once again digit++ is used for performance, as above
492         String numeral = "(("+digit+"++)|"+groupedNumeral+")";
493         String decimalNumeral = "("+numeral+"|"+numeral +
494             decimalSeparator + digit + "*+|"+ decimalSeparator +
495             digit + "++)";
496         String nonNumber = "(NaN|"+nanString+"|Infinity|"+
497                                infinityString+")";
498         String positiveFloat = "(" + positivePrefix + decimalNumeral +
499                             positiveSuffix + exponent + ")";
500         String negativeFloat = "(" + negativePrefix + decimalNumeral +
501                             negativeSuffix + exponent + ")";
502         String decimal = "(([-+]?" + decimalNumeral + exponent + ")|"+
503             positiveFloat + "|" + negativeFloat + ")";
504         String hexFloat =
505             "[-+]?0[xX][0-9a-fA-F]*\\.[0-9a-fA-F]+([pP][-+]?[0-9]+)?";
506         String positiveNonNumber = "(" + positivePrefix + nonNumber +
507                             positiveSuffix + ")";
508         String negativeNonNumber = "(" + negativePrefix + nonNumber +
509                             negativeSuffix + ")";
510         String signedNonNumber = "(([-+]?"+nonNumber+")|" +
511                                  positiveNonNumber + "|" +
512                                  negativeNonNumber + ")";
513         floatPattern = Pattern.compile(decimal + "|" + hexFloat + "|" +
514                                        signedNonNumber);
515         decimalPattern = Pattern.compile(decimal);
516     }
floatPattern()517     private Pattern floatPattern() {
518         if (floatPattern == null) {
519             buildFloatAndDecimalPattern();
520         }
521         return floatPattern;
522     }
decimalPattern()523     private Pattern decimalPattern() {
524         if (decimalPattern == null) {
525             buildFloatAndDecimalPattern();
526         }
527         return decimalPattern;
528     }
529 
530     // Constructors
531 
532     /**
533      * Constructs a {@code Scanner} that returns values scanned
534      * from the specified source delimited by the specified pattern.
535      *
536      * @param source A character source implementing the Readable interface
537      * @param pattern A delimiting pattern
538      */
Scanner(Readable source, Pattern pattern)539     private Scanner(Readable source, Pattern pattern) {
540         assert source != null : "source should not be null";
541         assert pattern != null : "pattern should not be null";
542         this.source = source;
543         delimPattern = pattern;
544         buf = CharBuffer.allocate(BUFFER_SIZE);
545         buf.limit(0);
546         matcher = delimPattern.matcher(buf);
547         matcher.useTransparentBounds(true);
548         matcher.useAnchoringBounds(false);
549         useLocale(Locale.getDefault(Locale.Category.FORMAT));
550     }
551 
552     /**
553      * Constructs a new {@code Scanner} that produces values scanned
554      * from the specified source.
555      *
556      * @param  source A character source implementing the {@link Readable}
557      *         interface
558      */
Scanner(Readable source)559     public Scanner(Readable source) {
560         this(Objects.requireNonNull(source, "source"), WHITESPACE_PATTERN);
561     }
562 
563     /**
564      * Constructs a new {@code Scanner} that produces values scanned
565      * from the specified input stream. Bytes from the stream are converted
566      * into characters using the underlying platform's
567      * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}.
568      *
569      * @param  source An input stream to be scanned
570      */
Scanner(InputStream source)571     public Scanner(InputStream source) {
572         this(new InputStreamReader(source), WHITESPACE_PATTERN);
573     }
574 
575     /**
576      * Constructs a new {@code Scanner} that produces values scanned
577      * from the specified input stream. Bytes from the stream are converted
578      * into characters using the specified charset.
579      *
580      * @param  source An input stream to be scanned
581      * @param charsetName The encoding type used to convert bytes from the
582      *        stream into characters to be scanned
583      * @throws IllegalArgumentException if the specified character set
584      *         does not exist
585      */
Scanner(InputStream source, String charsetName)586     public Scanner(InputStream source, String charsetName) {
587         this(source, toCharset(charsetName));
588     }
589 
590     /**
591      * Constructs a new {@code Scanner} that produces values scanned
592      * from the specified input stream. Bytes from the stream are converted
593      * into characters using the specified charset.
594      *
595      * @param  source an input stream to be scanned
596      * @param  charset the charset used to convert bytes from the file
597      *         into characters to be scanned
598      * @since  10
599      */
Scanner(InputStream source, Charset charset)600     public Scanner(InputStream source, Charset charset) {
601         this(makeReadable(Objects.requireNonNull(source, "source"), charset),
602              WHITESPACE_PATTERN);
603     }
604 
605     /**
606      * Returns a charset object for the given charset name.
607      * @throws NullPointerException          is csn is null
608      * @throws IllegalArgumentException      if the charset is not supported
609      */
toCharset(String csn)610     private static Charset toCharset(String csn) {
611         Objects.requireNonNull(csn, "charsetName");
612         try {
613             return Charset.forName(csn);
614         } catch (IllegalCharsetNameException|UnsupportedCharsetException e) {
615             // IllegalArgumentException should be thrown
616             throw new IllegalArgumentException(e);
617         }
618     }
619 
620     /*
621      * This method is added so that null-check on charset can be performed before
622      * creating InputStream as an existing test required it.
623      */
makeReadable(Path source, Charset charset)624     private static Readable makeReadable(Path source, Charset charset)
625             throws IOException {
626         Objects.requireNonNull(charset, "charset");
627         return makeReadable(Files.newInputStream(source), charset);
628     }
629 
makeReadable(InputStream source, Charset charset)630     private static Readable makeReadable(InputStream source, Charset charset) {
631         Objects.requireNonNull(charset, "charset");
632         return new InputStreamReader(source, charset);
633     }
634 
635     /**
636      * Constructs a new {@code Scanner} that produces values scanned
637      * from the specified file. Bytes from the file are converted into
638      * characters using the underlying platform's
639      * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}.
640      *
641      * @param  source A file to be scanned
642      * @throws FileNotFoundException if source is not found
643      */
Scanner(File source)644     public Scanner(File source) throws FileNotFoundException {
645         this((ReadableByteChannel)(new FileInputStream(source).getChannel()));
646     }
647 
648     /**
649      * Constructs a new {@code Scanner} that produces values scanned
650      * from the specified file. Bytes from the file are converted into
651      * characters using the specified charset.
652      *
653      * @param  source A file to be scanned
654      * @param charsetName The encoding type used to convert bytes from the file
655      *        into characters to be scanned
656      * @throws FileNotFoundException if source is not found
657      * @throws IllegalArgumentException if the specified encoding is
658      *         not found
659      */
Scanner(File source, String charsetName)660     public Scanner(File source, String charsetName)
661         throws FileNotFoundException
662     {
663         this(Objects.requireNonNull(source), toDecoder(charsetName));
664     }
665 
666     /**
667      * Constructs a new {@code Scanner} that produces values scanned
668      * from the specified file. Bytes from the file are converted into
669      * characters using the specified charset.
670      *
671      * @param  source A file to be scanned
672      * @param  charset The charset used to convert bytes from the file
673      *         into characters to be scanned
674      * @throws IOException
675      *         if an I/O error occurs opening the source
676      * @since  10
677      */
Scanner(File source, Charset charset)678     public Scanner(File source, Charset charset) throws IOException {
679         this(Objects.requireNonNull(source), charset.newDecoder());
680     }
681 
Scanner(File source, CharsetDecoder dec)682     private Scanner(File source, CharsetDecoder dec)
683         throws FileNotFoundException
684     {
685         this(makeReadable((ReadableByteChannel)(new FileInputStream(source).getChannel()), dec));
686     }
687 
toDecoder(String charsetName)688     private static CharsetDecoder toDecoder(String charsetName) {
689         // Android-changed: Throw an IAE instead of an NPE.
690         // Objects.requireNonNull(charsetName, "charsetName");
691         if (charsetName == null) {
692             throw new IllegalArgumentException("charsetName == null");
693         }
694         try {
695             return Charset.forName(charsetName).newDecoder();
696         } catch (IllegalCharsetNameException|UnsupportedCharsetException unused) {
697             throw new IllegalArgumentException(charsetName);
698         }
699     }
700 
makeReadable(ReadableByteChannel source, CharsetDecoder dec)701     private static Readable makeReadable(ReadableByteChannel source,
702                                          CharsetDecoder dec) {
703         return Channels.newReader(source, dec, -1);
704     }
705 
makeReadable(ReadableByteChannel source, Charset charset)706     private static Readable makeReadable(ReadableByteChannel source,
707                                          Charset charset) {
708         Objects.requireNonNull(charset, "charset");
709         return Channels.newReader(source, charset);
710     }
711 
712     /**
713      * Constructs a new {@code Scanner} that produces values scanned
714      * from the specified file. Bytes from the file are converted into
715      * characters using the underlying platform's
716      * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}.
717      *
718      * @param   source
719      *          the path to the file to be scanned
720      * @throws  IOException
721      *          if an I/O error occurs opening source
722      *
723      * @since   1.7
724      */
Scanner(Path source)725     public Scanner(Path source)
726         throws IOException
727     {
728         this(Files.newInputStream(source));
729     }
730 
731     /**
732      * Constructs a new {@code Scanner} that produces values scanned
733      * from the specified file. Bytes from the file are converted into
734      * characters using the specified charset.
735      *
736      * @param   source
737      *          the path to the file to be scanned
738      * @param   charsetName
739      *          The encoding type used to convert bytes from the file
740      *          into characters to be scanned
741      * @throws  IOException
742      *          if an I/O error occurs opening source
743      * @throws  IllegalArgumentException
744      *          if the specified encoding is not found
745      * @since   1.7
746      */
Scanner(Path source, String charsetName)747     public Scanner(Path source, String charsetName) throws IOException {
748         this(Objects.requireNonNull(source), toCharset(charsetName));
749     }
750 
751     /**
752      * Constructs a new {@code Scanner} that produces values scanned
753      * from the specified file. Bytes from the file are converted into
754      * characters using the specified charset.
755      *
756      * @param   source
757      *          the path to the file to be scanned
758      * @param   charset
759      *          the charset used to convert bytes from the file
760      *          into characters to be scanned
761      * @throws  IOException
762      *          if an I/O error occurs opening the source
763      * @since   10
764      */
Scanner(Path source, Charset charset)765     public Scanner(Path source, Charset charset)  throws IOException {
766         this(makeReadable(source, charset));
767     }
768 
769     /**
770      * Constructs a new {@code Scanner} that produces values scanned
771      * from the specified string.
772      *
773      * @param  source A string to scan
774      */
Scanner(String source)775     public Scanner(String source) {
776         this(new StringReader(source), WHITESPACE_PATTERN);
777     }
778 
779     /**
780      * Constructs a new {@code Scanner} that produces values scanned
781      * from the specified channel. Bytes from the source are converted into
782      * characters using the underlying platform's
783      * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}.
784      *
785      * @param  source A channel to scan
786      */
Scanner(ReadableByteChannel source)787     public Scanner(ReadableByteChannel source) {
788         this(makeReadable(Objects.requireNonNull(source, "source")),
789              WHITESPACE_PATTERN);
790     }
791 
makeReadable(ReadableByteChannel source)792     private static Readable makeReadable(ReadableByteChannel source) {
793         return makeReadable(source, Charset.defaultCharset().newDecoder());
794     }
795 
796     /**
797      * Constructs a new {@code Scanner} that produces values scanned
798      * from the specified channel. Bytes from the source are converted into
799      * characters using the specified charset.
800      *
801      * @param  source A channel to scan
802      * @param charsetName The encoding type used to convert bytes from the
803      *        channel into characters to be scanned
804      * @throws IllegalArgumentException if the specified character set
805      *         does not exist
806      */
Scanner(ReadableByteChannel source, String charsetName)807     public Scanner(ReadableByteChannel source, String charsetName) {
808         this(makeReadable(Objects.requireNonNull(source, "source"), toDecoder(charsetName)),
809              WHITESPACE_PATTERN);
810     }
811 
812     /**
813      * Constructs a new {@code Scanner} that produces values scanned
814      * from the specified channel. Bytes from the source are converted into
815      * characters using the specified charset.
816      *
817      * @param source a channel to scan
818      * @param charset the encoding type used to convert bytes from the
819      *        channel into characters to be scanned
820      * @since 10
821      */
Scanner(ReadableByteChannel source, Charset charset)822     public Scanner(ReadableByteChannel source, Charset charset) {
823         this(makeReadable(Objects.requireNonNull(source, "source"), charset),
824              WHITESPACE_PATTERN);
825     }
826 
827     // Private primitives used to support scanning
828 
saveState()829     private void saveState() {
830         savedScannerPosition = position;
831     }
832 
revertState()833     private void revertState() {
834         this.position = savedScannerPosition;
835         savedScannerPosition = -1;
836         skipped = false;
837     }
838 
revertState(boolean b)839     private boolean revertState(boolean b) {
840         this.position = savedScannerPosition;
841         savedScannerPosition = -1;
842         skipped = false;
843         return b;
844     }
845 
cacheResult()846     private void cacheResult() {
847         hasNextResult = matcher.group();
848         hasNextPosition = matcher.end();
849         hasNextPattern = matcher.pattern();
850     }
851 
cacheResult(String result)852     private void cacheResult(String result) {
853         hasNextResult = result;
854         hasNextPosition = matcher.end();
855         hasNextPattern = matcher.pattern();
856     }
857 
858     // Clears both regular cache and type cache
clearCaches()859     private void clearCaches() {
860         hasNextPattern = null;
861         typeCache = null;
862     }
863 
864     // Also clears both the regular cache and the type cache
getCachedResult()865     private String getCachedResult() {
866         position = hasNextPosition;
867         hasNextPattern = null;
868         typeCache = null;
869         return hasNextResult;
870     }
871 
872     // Also clears both the regular cache and the type cache
useTypeCache()873     private void useTypeCache() {
874         if (closed)
875             throw new IllegalStateException("Scanner closed");
876         position = hasNextPosition;
877         hasNextPattern = null;
878         typeCache = null;
879     }
880 
881     // Tries to read more input. May block.
readInput()882     private void readInput() {
883         if (buf.limit() == buf.capacity())
884             makeSpace();
885         // Prepare to receive data
886         int p = buf.position();
887         buf.position(buf.limit());
888         buf.limit(buf.capacity());
889 
890         int n = 0;
891         try {
892             n = source.read(buf);
893         } catch (IOException ioe) {
894             lastException = ioe;
895             n = -1;
896         }
897         if (n == -1) {
898             sourceClosed = true;
899             needInput = false;
900         }
901         if (n > 0)
902             needInput = false;
903         // Restore current position and limit for reading
904         buf.limit(buf.position());
905         buf.position(p);
906         // Android-added: reset() the matcher after reading.
907         // The matcher implementation eagerly calls toString() so we'll have
908         // to update its input whenever the buffer limit, position etc. changes.
909         matcher.reset(buf);
910     }
911 
912     // After this method is called there will either be an exception
913     // or else there will be space in the buffer
makeSpace()914     private boolean makeSpace() {
915         clearCaches();
916         int offset = savedScannerPosition == -1 ?
917             position : savedScannerPosition;
918         buf.position(offset);
919         // Gain space by compacting buffer
920         if (offset > 0) {
921             buf.compact();
922             translateSavedIndexes(offset);
923             position -= offset;
924             buf.flip();
925             return true;
926         }
927         // Gain space by growing buffer
928         int newSize = buf.capacity() * 2;
929         CharBuffer newBuf = CharBuffer.allocate(newSize);
930         newBuf.put(buf);
931         newBuf.flip();
932         translateSavedIndexes(offset);
933         position -= offset;
934         buf = newBuf;
935         matcher.reset(buf);
936         return true;
937     }
938 
939     // When a buffer compaction/reallocation occurs the saved indexes must
940     // be modified appropriately
translateSavedIndexes(int offset)941     private void translateSavedIndexes(int offset) {
942         if (savedScannerPosition != -1)
943             savedScannerPosition -= offset;
944     }
945 
946     // If we are at the end of input then NoSuchElement;
947     // If there is still input left then InputMismatch
throwFor()948     private void throwFor() {
949         skipped = false;
950         if ((sourceClosed) && (position == buf.limit()))
951             throw new NoSuchElementException();
952         else
953             throw new InputMismatchException();
954     }
955 
956     // Returns true if a complete token or partial token is in the buffer.
957     // It is not necessary to find a complete token since a partial token
958     // means that there will be another token with or without more input.
hasTokenInBuffer()959     private boolean hasTokenInBuffer() {
960         matchValid = false;
961         matcher.usePattern(delimPattern);
962         matcher.region(position, buf.limit());
963         // Skip delims first
964         if (matcher.lookingAt()) {
965             if (matcher.hitEnd() && !sourceClosed) {
966                 // more input might change the match of delims, in which
967                 // might change whether or not if there is token left in
968                 // buffer (don't update the "position" in this case)
969                 needInput = true;
970                 return false;
971             }
972             position = matcher.end();
973         }
974         // If we are sitting at the end, no more tokens in buffer
975         if (position == buf.limit())
976             return false;
977         return true;
978     }
979 
980     /*
981      * Returns a "complete token" that matches the specified pattern
982      *
983      * A token is complete if surrounded by delims; a partial token
984      * is prefixed by delims but not postfixed by them
985      *
986      * The position is advanced to the end of that complete token
987      *
988      * Pattern == null means accept any token at all
989      *
990      * Triple return:
991      * 1. valid string means it was found
992      * 2. null with needInput=false means we won't ever find it
993      * 3. null with needInput=true means try again after readInput
994      */
getCompleteTokenInBuffer(Pattern pattern)995     private String getCompleteTokenInBuffer(Pattern pattern) {
996         matchValid = false;
997         // Skip delims first
998         matcher.usePattern(delimPattern);
999         if (!skipped) { // Enforcing only one skip of leading delims
1000             matcher.region(position, buf.limit());
1001             if (matcher.lookingAt()) {
1002                 // If more input could extend the delimiters then we must wait
1003                 // for more input
1004                 if (matcher.hitEnd() && !sourceClosed) {
1005                     needInput = true;
1006                     return null;
1007                 }
1008                 // The delims were whole and the matcher should skip them
1009                 skipped = true;
1010                 position = matcher.end();
1011             }
1012         }
1013 
1014         // If we are sitting at the end, no more tokens in buffer
1015         if (position == buf.limit()) {
1016             if (sourceClosed)
1017                 return null;
1018             needInput = true;
1019             return null;
1020         }
1021         // Must look for next delims. Simply attempting to match the
1022         // pattern at this point may find a match but it might not be
1023         // the first longest match because of missing input, or it might
1024         // match a partial token instead of the whole thing.
1025 
1026         // Then look for next delims
1027         matcher.region(position, buf.limit());
1028         boolean foundNextDelim = matcher.find();
1029         if (foundNextDelim && (matcher.end() == position)) {
1030             // Zero length delimiter match; we should find the next one
1031             // using the automatic advance past a zero length match;
1032             // Otherwise we have just found the same one we just skipped
1033             foundNextDelim = matcher.find();
1034         }
1035         if (foundNextDelim) {
1036             // In the rare case that more input could cause the match
1037             // to be lost and there is more input coming we must wait
1038             // for more input. Note that hitting the end is okay as long
1039             // as the match cannot go away. It is the beginning of the
1040             // next delims we want to be sure about, we don't care if
1041             // they potentially extend further.
1042             if (matcher.requireEnd() && !sourceClosed) {
1043                 needInput = true;
1044                 return null;
1045             }
1046             int tokenEnd = matcher.start();
1047             // There is a complete token.
1048             if (pattern == null) {
1049                 // Must continue with match to provide valid MatchResult
1050                 pattern = FIND_ANY_PATTERN;
1051             }
1052             //  Attempt to match against the desired pattern
1053             matcher.usePattern(pattern);
1054             matcher.region(position, tokenEnd);
1055             if (matcher.matches()) {
1056                 String s = matcher.group();
1057                 position = matcher.end();
1058                 return s;
1059             } else { // Complete token but it does not match
1060                 return null;
1061             }
1062         }
1063 
1064         // If we can't find the next delims but no more input is coming,
1065         // then we can treat the remainder as a whole token
1066         if (sourceClosed) {
1067             if (pattern == null) {
1068                 // Must continue with match to provide valid MatchResult
1069                 pattern = FIND_ANY_PATTERN;
1070             }
1071             // Last token; Match the pattern here or throw
1072             matcher.usePattern(pattern);
1073             matcher.region(position, buf.limit());
1074             if (matcher.matches()) {
1075                 String s = matcher.group();
1076                 position = matcher.end();
1077                 return s;
1078             }
1079             // Last piece does not match
1080             return null;
1081         }
1082 
1083         // There is a partial token in the buffer; must read more
1084         // to complete it
1085         needInput = true;
1086         return null;
1087     }
1088 
1089     // Finds the specified pattern in the buffer up to horizon.
1090     // Returns true if the specified input pattern was matched,
1091     // and leaves the matcher field with the current match state.
findPatternInBuffer(Pattern pattern, int horizon)1092     private boolean findPatternInBuffer(Pattern pattern, int horizon) {
1093         matchValid = false;
1094         matcher.usePattern(pattern);
1095         int bufferLimit = buf.limit();
1096         int horizonLimit = -1;
1097         int searchLimit = bufferLimit;
1098         if (horizon > 0) {
1099             horizonLimit = position + horizon;
1100             if (horizonLimit < bufferLimit)
1101                 searchLimit = horizonLimit;
1102         }
1103         matcher.region(position, searchLimit);
1104         if (matcher.find()) {
1105             if (matcher.hitEnd() && (!sourceClosed)) {
1106                 // The match may be longer if didn't hit horizon or real end
1107                 if (searchLimit != horizonLimit) {
1108                      // Hit an artificial end; try to extend the match
1109                     needInput = true;
1110                     return false;
1111                 }
1112                 // The match could go away depending on what is next
1113                 if ((searchLimit == horizonLimit) && matcher.requireEnd()) {
1114                     // Rare case: we hit the end of input and it happens
1115                     // that it is at the horizon and the end of input is
1116                     // required for the match.
1117                     needInput = true;
1118                     return false;
1119                 }
1120             }
1121             // Did not hit end, or hit real end, or hit horizon
1122             position = matcher.end();
1123             return true;
1124         }
1125 
1126         if (sourceClosed)
1127             return false;
1128 
1129         // If there is no specified horizon, or if we have not searched
1130         // to the specified horizon yet, get more input
1131         if ((horizon == 0) || (searchLimit != horizonLimit))
1132             needInput = true;
1133         return false;
1134     }
1135 
1136     // Attempts to match a pattern anchored at the current position.
1137     // Returns true if the specified input pattern was matched,
1138     // and leaves the matcher field with the current match state.
matchPatternInBuffer(Pattern pattern)1139     private boolean matchPatternInBuffer(Pattern pattern) {
1140         matchValid = false;
1141         matcher.usePattern(pattern);
1142         matcher.region(position, buf.limit());
1143         if (matcher.lookingAt()) {
1144             if (matcher.hitEnd() && (!sourceClosed)) {
1145                 // Get more input and try again
1146                 needInput = true;
1147                 return false;
1148             }
1149             position = matcher.end();
1150             return true;
1151         }
1152 
1153         if (sourceClosed)
1154             return false;
1155 
1156         // Read more to find pattern
1157         needInput = true;
1158         return false;
1159     }
1160 
1161     // Throws if the scanner is closed
ensureOpen()1162     private void ensureOpen() {
1163         if (closed)
1164             throw new IllegalStateException("Scanner closed");
1165     }
1166 
1167     // Public methods
1168 
1169     /**
1170      * Closes this scanner.
1171      *
1172      * <p> If this scanner has not yet been closed then if its underlying
1173      * {@linkplain java.lang.Readable readable} also implements the {@link
1174      * java.io.Closeable} interface then the readable's {@code close} method
1175      * will be invoked.  If this scanner is already closed then invoking this
1176      * method will have no effect.
1177      *
1178      * <p>Attempting to perform search operations after a scanner has
1179      * been closed will result in an {@link IllegalStateException}.
1180      *
1181      */
close()1182     public void close() {
1183         if (closed)
1184             return;
1185         if (source instanceof Closeable) {
1186             try {
1187                 ((Closeable)source).close();
1188             } catch (IOException ioe) {
1189                 lastException = ioe;
1190             }
1191         }
1192         sourceClosed = true;
1193         source = null;
1194         closed = true;
1195     }
1196 
1197     /**
1198      * Returns the {@code IOException} last thrown by this
1199      * {@code Scanner}'s underlying {@code Readable}. This method
1200      * returns {@code null} if no such exception exists.
1201      *
1202      * @return the last exception thrown by this scanner's readable
1203      */
ioException()1204     public IOException ioException() {
1205         return lastException;
1206     }
1207 
1208     /**
1209      * Returns the {@code Pattern} this {@code Scanner} is currently
1210      * using to match delimiters.
1211      *
1212      * @return this scanner's delimiting pattern.
1213      */
delimiter()1214     public Pattern delimiter() {
1215         return delimPattern;
1216     }
1217 
1218     /**
1219      * Sets this scanner's delimiting pattern to the specified pattern.
1220      *
1221      * @param pattern A delimiting pattern
1222      * @return this scanner
1223      */
useDelimiter(Pattern pattern)1224     public Scanner useDelimiter(Pattern pattern) {
1225         modCount++;
1226         delimPattern = pattern;
1227         return this;
1228     }
1229 
1230     /**
1231      * Sets this scanner's delimiting pattern to a pattern constructed from
1232      * the specified {@code String}.
1233      *
1234      * <p> An invocation of this method of the form
1235      * {@code useDelimiter(pattern)} behaves in exactly the same way as the
1236      * invocation {@code useDelimiter(Pattern.compile(pattern))}.
1237      *
1238      * <p> Invoking the {@link #reset} method will set the scanner's delimiter
1239      * to the <a href= "#default-delimiter">default</a>.
1240      *
1241      * @param pattern A string specifying a delimiting pattern
1242      * @return this scanner
1243      */
useDelimiter(String pattern)1244     public Scanner useDelimiter(String pattern) {
1245         modCount++;
1246         delimPattern = patternCache.forName(pattern);
1247         return this;
1248     }
1249 
1250     /**
1251      * Returns this scanner's locale.
1252      *
1253      * <p>A scanner's locale affects many elements of its default
1254      * primitive matching regular expressions; see
1255      * <a href= "#localized-numbers">localized numbers</a> above.
1256      *
1257      * @return this scanner's locale
1258      */
locale()1259     public Locale locale() {
1260         return this.locale;
1261     }
1262 
1263     /**
1264      * Sets this scanner's locale to the specified locale.
1265      *
1266      * <p>A scanner's locale affects many elements of its default
1267      * primitive matching regular expressions; see
1268      * <a href= "#localized-numbers">localized numbers</a> above.
1269      *
1270      * <p>Invoking the {@link #reset} method will set the scanner's locale to
1271      * the <a href= "#initial-locale">initial locale</a>.
1272      *
1273      * @param locale A string specifying the locale to use
1274      * @return this scanner
1275      */
useLocale(Locale locale)1276     public Scanner useLocale(Locale locale) {
1277         if (locale.equals(this.locale))
1278             return this;
1279 
1280         modCount++;
1281         this.locale = locale;
1282 
1283         DecimalFormat df = null;
1284         NumberFormat nf = NumberFormat.getNumberInstance(locale);
1285         DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(locale);
1286 
1287         // Android-changed: nf is DecimalFormat.
1288         /*
1289         if (nf instanceof DecimalFormat) {
1290              df = (DecimalFormat) nf;
1291         } else {
1292 
1293             // In case where NumberFormat.getNumberInstance() returns
1294             // other instance (non DecimalFormat) based on the provider
1295             // used and java.text.spi.NumberFormatProvider implementations,
1296             // DecimalFormat constructor is used to obtain the instance
1297             LocaleProviderAdapter adapter = LocaleProviderAdapter
1298                     .getAdapter(NumberFormatProvider.class, locale);
1299             if (!(adapter instanceof ResourceBundleBasedAdapter)) {
1300                 adapter = LocaleProviderAdapter.getResourceBundleBased();
1301             }
1302             String[] all = adapter.getLocaleResources(locale)
1303                     .getNumberPatterns();
1304             df = new DecimalFormat(all[0], dfs);
1305         }
1306         */
1307         df = (DecimalFormat) nf;
1308 
1309         // These must be literalized to avoid collision with regex
1310         // metacharacters such as dot or parenthesis
1311         groupSeparator =   "\\x{" + Integer.toHexString(dfs.getGroupingSeparator()) + "}";
1312         decimalSeparator = "\\x{" + Integer.toHexString(dfs.getDecimalSeparator()) + "}";
1313 
1314         // Quoting the nonzero length locale-specific things
1315         // to avoid potential conflict with metacharacters
1316         nanString = Pattern.quote(dfs.getNaN());
1317         infinityString = Pattern.quote(dfs.getInfinity());
1318         positivePrefix = df.getPositivePrefix();
1319         if (!positivePrefix.isEmpty())
1320             positivePrefix = Pattern.quote(positivePrefix);
1321         negativePrefix = df.getNegativePrefix();
1322         if (!negativePrefix.isEmpty())
1323             negativePrefix = Pattern.quote(negativePrefix);
1324         positiveSuffix = df.getPositiveSuffix();
1325         if (!positiveSuffix.isEmpty())
1326             positiveSuffix = Pattern.quote(positiveSuffix);
1327         negativeSuffix = df.getNegativeSuffix();
1328         if (!negativeSuffix.isEmpty())
1329             negativeSuffix = Pattern.quote(negativeSuffix);
1330 
1331         // Force rebuilding and recompilation of locale dependent
1332         // primitive patterns
1333         integerPattern = null;
1334         floatPattern = null;
1335 
1336         return this;
1337     }
1338 
1339     /**
1340      * Returns this scanner's default radix.
1341      *
1342      * <p>A scanner's radix affects elements of its default
1343      * number matching regular expressions; see
1344      * <a href= "#localized-numbers">localized numbers</a> above.
1345      *
1346      * @return the default radix of this scanner
1347      */
radix()1348     public int radix() {
1349         return this.defaultRadix;
1350     }
1351 
1352     /**
1353      * Sets this scanner's default radix to the specified radix.
1354      *
1355      * <p>A scanner's radix affects elements of its default
1356      * number matching regular expressions; see
1357      * <a href= "#localized-numbers">localized numbers</a> above.
1358      *
1359      * <p>If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX}
1360      * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an
1361      * {@code IllegalArgumentException} is thrown.
1362      *
1363      * <p>Invoking the {@link #reset} method will set the scanner's radix to
1364      * {@code 10}.
1365      *
1366      * @param radix The radix to use when scanning numbers
1367      * @return this scanner
1368      * @throws IllegalArgumentException if radix is out of range
1369      */
useRadix(int radix)1370     public Scanner useRadix(int radix) {
1371         if ((radix < Character.MIN_RADIX) || (radix > Character.MAX_RADIX))
1372             throw new IllegalArgumentException("radix:"+radix);
1373 
1374         if (this.defaultRadix == radix)
1375             return this;
1376         modCount++;
1377         this.defaultRadix = radix;
1378         // Force rebuilding and recompilation of radix dependent patterns
1379         integerPattern = null;
1380         return this;
1381     }
1382 
1383     // The next operation should occur in the specified radix but
1384     // the default is left untouched.
setRadix(int radix)1385     private void setRadix(int radix) {
1386         if ((radix < Character.MIN_RADIX) || (radix > Character.MAX_RADIX))
1387             throw new IllegalArgumentException("radix:"+radix);
1388 
1389         if (this.radix != radix) {
1390             // Force rebuilding and recompilation of radix dependent patterns
1391             integerPattern = null;
1392             this.radix = radix;
1393         }
1394     }
1395 
1396     /**
1397      * Returns the match result of the last scanning operation performed
1398      * by this scanner. This method throws {@code IllegalStateException}
1399      * if no match has been performed, or if the last match was
1400      * not successful.
1401      *
1402      * <p>The various {@code next} methods of {@code Scanner}
1403      * make a match result available if they complete without throwing an
1404      * exception. For instance, after an invocation of the {@link #nextInt}
1405      * method that returned an int, this method returns a
1406      * {@code MatchResult} for the search of the
1407      * <a href="#Integer-regex"><i>Integer</i></a> regular expression
1408      * defined above. Similarly the {@link #findInLine findInLine()},
1409      * {@link #findWithinHorizon findWithinHorizon()}, and {@link #skip skip()}
1410      * methods will make a match available if they succeed.
1411      *
1412      * @return a match result for the last match operation
1413      * @throws IllegalStateException  If no match result is available
1414      */
match()1415     public MatchResult match() {
1416         if (!matchValid)
1417             throw new IllegalStateException("No match result available");
1418         return matcher.toMatchResult();
1419     }
1420 
1421     /**
1422      * <p>Returns the string representation of this {@code Scanner}. The
1423      * string representation of a {@code Scanner} contains information
1424      * that may be useful for debugging. The exact format is unspecified.
1425      *
1426      * @return  The string representation of this scanner
1427      */
toString()1428     public String toString() {
1429         StringBuilder sb = new StringBuilder();
1430         sb.append("java.util.Scanner");
1431         sb.append("[delimiters=" + delimPattern + "]");
1432         sb.append("[position=" + position + "]");
1433         sb.append("[match valid=" + matchValid + "]");
1434         sb.append("[need input=" + needInput + "]");
1435         sb.append("[source closed=" + sourceClosed + "]");
1436         sb.append("[skipped=" + skipped + "]");
1437         sb.append("[group separator=" + groupSeparator + "]");
1438         sb.append("[decimal separator=" + decimalSeparator + "]");
1439         sb.append("[positive prefix=" + positivePrefix + "]");
1440         sb.append("[negative prefix=" + negativePrefix + "]");
1441         sb.append("[positive suffix=" + positiveSuffix + "]");
1442         sb.append("[negative suffix=" + negativeSuffix + "]");
1443         sb.append("[NaN string=" + nanString + "]");
1444         sb.append("[infinity string=" + infinityString + "]");
1445         return sb.toString();
1446     }
1447 
1448     /**
1449      * Returns true if this scanner has another token in its input.
1450      * This method may block while waiting for input to scan.
1451      * The scanner does not advance past any input.
1452      *
1453      * @return true if and only if this scanner has another token
1454      * @throws IllegalStateException if this scanner is closed
1455      * @see java.util.Iterator
1456      */
hasNext()1457     public boolean hasNext() {
1458         ensureOpen();
1459         saveState();
1460         modCount++;
1461         while (!sourceClosed) {
1462             if (hasTokenInBuffer()) {
1463                 return revertState(true);
1464             }
1465             readInput();
1466         }
1467         boolean result = hasTokenInBuffer();
1468         return revertState(result);
1469     }
1470 
1471     /**
1472      * Finds and returns the next complete token from this scanner.
1473      * A complete token is preceded and followed by input that matches
1474      * the delimiter pattern. This method may block while waiting for input
1475      * to scan, even if a previous invocation of {@link #hasNext} returned
1476      * {@code true}.
1477      *
1478      * @return the next token
1479      * @throws NoSuchElementException if no more tokens are available
1480      * @throws IllegalStateException if this scanner is closed
1481      * @see java.util.Iterator
1482      */
next()1483     public String next() {
1484         ensureOpen();
1485         clearCaches();
1486         modCount++;
1487         while (true) {
1488             String token = getCompleteTokenInBuffer(null);
1489             if (token != null) {
1490                 matchValid = true;
1491                 skipped = false;
1492                 return token;
1493             }
1494             if (needInput)
1495                 readInput();
1496             else
1497                 throwFor();
1498         }
1499     }
1500 
1501     /**
1502      * The remove operation is not supported by this implementation of
1503      * {@code Iterator}.
1504      *
1505      * @throws UnsupportedOperationException if this method is invoked.
1506      * @see java.util.Iterator
1507      */
remove()1508     public void remove() {
1509         throw new UnsupportedOperationException();
1510     }
1511 
1512     /**
1513      * Returns true if the next token matches the pattern constructed from the
1514      * specified string. The scanner does not advance past any input.
1515      *
1516      * <p> An invocation of this method of the form {@code hasNext(pattern)}
1517      * behaves in exactly the same way as the invocation
1518      * {@code hasNext(Pattern.compile(pattern))}.
1519      *
1520      * @param pattern a string specifying the pattern to scan
1521      * @return true if and only if this scanner has another token matching
1522      *         the specified pattern
1523      * @throws IllegalStateException if this scanner is closed
1524      */
hasNext(String pattern)1525     public boolean hasNext(String pattern)  {
1526         return hasNext(patternCache.forName(pattern));
1527     }
1528 
1529     /**
1530      * Returns the next token if it matches the pattern constructed from the
1531      * specified string.  If the match is successful, the scanner advances
1532      * past the input that matched the pattern.
1533      *
1534      * <p> An invocation of this method of the form {@code next(pattern)}
1535      * behaves in exactly the same way as the invocation
1536      * {@code next(Pattern.compile(pattern))}.
1537      *
1538      * @param pattern a string specifying the pattern to scan
1539      * @return the next token
1540      * @throws NoSuchElementException if no such tokens are available
1541      * @throws IllegalStateException if this scanner is closed
1542      */
next(String pattern)1543     public String next(String pattern)  {
1544         return next(patternCache.forName(pattern));
1545     }
1546 
1547     /**
1548      * Returns true if the next complete token matches the specified pattern.
1549      * A complete token is prefixed and postfixed by input that matches
1550      * the delimiter pattern. This method may block while waiting for input.
1551      * The scanner does not advance past any input.
1552      *
1553      * @param pattern the pattern to scan for
1554      * @return true if and only if this scanner has another token matching
1555      *         the specified pattern
1556      * @throws IllegalStateException if this scanner is closed
1557      */
hasNext(Pattern pattern)1558     public boolean hasNext(Pattern pattern) {
1559         ensureOpen();
1560         if (pattern == null)
1561             throw new NullPointerException();
1562         hasNextPattern = null;
1563         saveState();
1564         modCount++;
1565 
1566         while (true) {
1567             if (getCompleteTokenInBuffer(pattern) != null) {
1568                 matchValid = true;
1569                 cacheResult();
1570                 return revertState(true);
1571             }
1572             if (needInput)
1573                 readInput();
1574             else
1575                 return revertState(false);
1576         }
1577     }
1578 
1579     /**
1580      * Returns the next token if it matches the specified pattern. This
1581      * method may block while waiting for input to scan, even if a previous
1582      * invocation of {@link #hasNext(Pattern)} returned {@code true}.
1583      * If the match is successful, the scanner advances past the input that
1584      * matched the pattern.
1585      *
1586      * @param pattern the pattern to scan for
1587      * @return the next token
1588      * @throws NoSuchElementException if no more tokens are available
1589      * @throws IllegalStateException if this scanner is closed
1590      */
next(Pattern pattern)1591     public String next(Pattern pattern) {
1592         ensureOpen();
1593         if (pattern == null)
1594             throw new NullPointerException();
1595 
1596         modCount++;
1597         // Did we already find this pattern?
1598         if (hasNextPattern == pattern)
1599             return getCachedResult();
1600         clearCaches();
1601 
1602         // Search for the pattern
1603         while (true) {
1604             String token = getCompleteTokenInBuffer(pattern);
1605             if (token != null) {
1606                 matchValid = true;
1607                 skipped = false;
1608                 return token;
1609             }
1610             if (needInput)
1611                 readInput();
1612             else
1613                 throwFor();
1614         }
1615     }
1616 
1617     /**
1618      * Returns true if there is another line in the input of this scanner.
1619      * This method may block while waiting for input. The scanner does not
1620      * advance past any input.
1621      *
1622      * @return true if and only if this scanner has another line of input
1623      * @throws IllegalStateException if this scanner is closed
1624      */
hasNextLine()1625     public boolean hasNextLine() {
1626         saveState();
1627 
1628         modCount++;
1629         String result = findWithinHorizon(linePattern(), 0);
1630         if (result != null) {
1631             MatchResult mr = this.match();
1632             String lineSep = mr.group(1);
1633             if (lineSep != null) {
1634                 result = result.substring(0, result.length() -
1635                                           lineSep.length());
1636                 cacheResult(result);
1637 
1638             } else {
1639                 cacheResult();
1640             }
1641         }
1642         revertState();
1643         return (result != null);
1644     }
1645 
1646     /**
1647      * Advances this scanner past the current line and returns the input
1648      * that was skipped.
1649      *
1650      * This method returns the rest of the current line, excluding any line
1651      * separator at the end. The position is set to the beginning of the next
1652      * line.
1653      *
1654      * <p>Since this method continues to search through the input looking
1655      * for a line separator, it may buffer all of the input searching for
1656      * the line to skip if no line separators are present.
1657      *
1658      * @return the line that was skipped
1659      * @throws NoSuchElementException if no line was found
1660      * @throws IllegalStateException if this scanner is closed
1661      */
nextLine()1662     public String nextLine() {
1663         modCount++;
1664         if (hasNextPattern == linePattern())
1665             return getCachedResult();
1666         clearCaches();
1667 
1668         String result = findWithinHorizon(linePattern, 0);
1669         if (result == null)
1670             throw new NoSuchElementException("No line found");
1671         MatchResult mr = this.match();
1672         String lineSep = mr.group(1);
1673         if (lineSep != null)
1674             result = result.substring(0, result.length() - lineSep.length());
1675         if (result == null)
1676             throw new NoSuchElementException();
1677         else
1678             return result;
1679     }
1680 
1681     // Public methods that ignore delimiters
1682 
1683     /**
1684      * Attempts to find the next occurrence of a pattern constructed from the
1685      * specified string, ignoring delimiters.
1686      *
1687      * <p>An invocation of this method of the form {@code findInLine(pattern)}
1688      * behaves in exactly the same way as the invocation
1689      * {@code findInLine(Pattern.compile(pattern))}.
1690      *
1691      * @param pattern a string specifying the pattern to search for
1692      * @return the text that matched the specified pattern
1693      * @throws IllegalStateException if this scanner is closed
1694      */
findInLine(String pattern)1695     public String findInLine(String pattern) {
1696         return findInLine(patternCache.forName(pattern));
1697     }
1698 
1699     /**
1700      * Attempts to find the next occurrence of the specified pattern ignoring
1701      * delimiters. If the pattern is found before the next line separator, the
1702      * scanner advances past the input that matched and returns the string that
1703      * matched the pattern.
1704      * If no such pattern is detected in the input up to the next line
1705      * separator, then {@code null} is returned and the scanner's
1706      * position is unchanged. This method may block waiting for input that
1707      * matches the pattern.
1708      *
1709      * <p>Since this method continues to search through the input looking
1710      * for the specified pattern, it may buffer all of the input searching for
1711      * the desired token if no line separators are present.
1712      *
1713      * @param pattern the pattern to scan for
1714      * @return the text that matched the specified pattern
1715      * @throws IllegalStateException if this scanner is closed
1716      */
findInLine(Pattern pattern)1717     public String findInLine(Pattern pattern) {
1718         ensureOpen();
1719         if (pattern == null)
1720             throw new NullPointerException();
1721         clearCaches();
1722         modCount++;
1723         // Expand buffer to include the next newline or end of input
1724         int endPosition = 0;
1725         saveState();
1726         while (true) {
1727             if (findPatternInBuffer(separatorPattern(), 0)) {
1728                 endPosition = matcher.start();
1729                 break; // up to next newline
1730             }
1731             if (needInput) {
1732                 readInput();
1733             } else {
1734                 endPosition = buf.limit();
1735                 break; // up to end of input
1736             }
1737         }
1738         revertState();
1739         int horizonForLine = endPosition - position;
1740         // If there is nothing between the current pos and the next
1741         // newline simply return null, invoking findWithinHorizon
1742         // with "horizon=0" will scan beyond the line bound.
1743         if (horizonForLine == 0)
1744             return null;
1745         // Search for the pattern
1746         return findWithinHorizon(pattern, horizonForLine);
1747     }
1748 
1749     /**
1750      * Attempts to find the next occurrence of a pattern constructed from the
1751      * specified string, ignoring delimiters.
1752      *
1753      * <p>An invocation of this method of the form
1754      * {@code findWithinHorizon(pattern)} behaves in exactly the same way as
1755      * the invocation
1756      * {@code findWithinHorizon(Pattern.compile(pattern), horizon)}.
1757      *
1758      * @param pattern a string specifying the pattern to search for
1759      * @param horizon the search horizon
1760      * @return the text that matched the specified pattern
1761      * @throws IllegalStateException if this scanner is closed
1762      * @throws IllegalArgumentException if horizon is negative
1763      */
findWithinHorizon(String pattern, int horizon)1764     public String findWithinHorizon(String pattern, int horizon) {
1765         return findWithinHorizon(patternCache.forName(pattern), horizon);
1766     }
1767 
1768     /**
1769      * Attempts to find the next occurrence of the specified pattern.
1770      *
1771      * <p>This method searches through the input up to the specified
1772      * search horizon, ignoring delimiters. If the pattern is found the
1773      * scanner advances past the input that matched and returns the string
1774      * that matched the pattern. If no such pattern is detected then the
1775      * null is returned and the scanner's position remains unchanged. This
1776      * method may block waiting for input that matches the pattern.
1777      *
1778      * <p>A scanner will never search more than {@code horizon} code
1779      * points beyond its current position. Note that a match may be clipped
1780      * by the horizon; that is, an arbitrary match result may have been
1781      * different if the horizon had been larger. The scanner treats the
1782      * horizon as a transparent, non-anchoring bound (see {@link
1783      * Matcher#useTransparentBounds} and {@link Matcher#useAnchoringBounds}).
1784      *
1785      * <p>If horizon is {@code 0}, then the horizon is ignored and
1786      * this method continues to search through the input looking for the
1787      * specified pattern without bound. In this case it may buffer all of
1788      * the input searching for the pattern.
1789      *
1790      * <p>If horizon is negative, then an IllegalArgumentException is
1791      * thrown.
1792      *
1793      * @param pattern the pattern to scan for
1794      * @param horizon the search horizon
1795      * @return the text that matched the specified pattern
1796      * @throws IllegalStateException if this scanner is closed
1797      * @throws IllegalArgumentException if horizon is negative
1798      */
findWithinHorizon(Pattern pattern, int horizon)1799     public String findWithinHorizon(Pattern pattern, int horizon) {
1800         ensureOpen();
1801         if (pattern == null)
1802             throw new NullPointerException();
1803         if (horizon < 0)
1804             throw new IllegalArgumentException("horizon < 0");
1805         clearCaches();
1806         modCount++;
1807 
1808         // Search for the pattern
1809         while (true) {
1810             if (findPatternInBuffer(pattern, horizon)) {
1811                 matchValid = true;
1812                 return matcher.group();
1813             }
1814             if (needInput)
1815                 readInput();
1816             else
1817                 break; // up to end of input
1818         }
1819         return null;
1820     }
1821 
1822     /**
1823      * Skips input that matches the specified pattern, ignoring delimiters.
1824      * This method will skip input if an anchored match of the specified
1825      * pattern succeeds.
1826      *
1827      * <p>If a match to the specified pattern is not found at the
1828      * current position, then no input is skipped and a
1829      * {@code NoSuchElementException} is thrown.
1830      *
1831      * <p>Since this method seeks to match the specified pattern starting at
1832      * the scanner's current position, patterns that can match a lot of
1833      * input (".*", for example) may cause the scanner to buffer a large
1834      * amount of input.
1835      *
1836      * <p>Note that it is possible to skip something without risking a
1837      * {@code NoSuchElementException} by using a pattern that can
1838      * match nothing, e.g., {@code sc.skip("[ \t]*")}.
1839      *
1840      * @param pattern a string specifying the pattern to skip over
1841      * @return this scanner
1842      * @throws NoSuchElementException if the specified pattern is not found
1843      * @throws IllegalStateException if this scanner is closed
1844      */
skip(Pattern pattern)1845     public Scanner skip(Pattern pattern) {
1846         ensureOpen();
1847         if (pattern == null)
1848             throw new NullPointerException();
1849         clearCaches();
1850         modCount++;
1851 
1852         // Search for the pattern
1853         while (true) {
1854             if (matchPatternInBuffer(pattern)) {
1855                 matchValid = true;
1856                 position = matcher.end();
1857                 return this;
1858             }
1859             if (needInput)
1860                 readInput();
1861             else
1862                 throw new NoSuchElementException();
1863         }
1864     }
1865 
1866     /**
1867      * Skips input that matches a pattern constructed from the specified
1868      * string.
1869      *
1870      * <p> An invocation of this method of the form {@code skip(pattern)}
1871      * behaves in exactly the same way as the invocation
1872      * {@code skip(Pattern.compile(pattern))}.
1873      *
1874      * @param pattern a string specifying the pattern to skip over
1875      * @return this scanner
1876      * @throws IllegalStateException if this scanner is closed
1877      */
skip(String pattern)1878     public Scanner skip(String pattern) {
1879         return skip(patternCache.forName(pattern));
1880     }
1881 
1882     // Convenience methods for scanning primitives
1883 
1884     /**
1885      * Returns true if the next token in this scanner's input can be
1886      * interpreted as a boolean value using a case insensitive pattern
1887      * created from the string "true|false".  The scanner does not
1888      * advance past the input that matched.
1889      *
1890      * @return true if and only if this scanner's next token is a valid
1891      *         boolean value
1892      * @throws IllegalStateException if this scanner is closed
1893      */
hasNextBoolean()1894     public boolean hasNextBoolean()  {
1895         return hasNext(boolPattern());
1896     }
1897 
1898     /**
1899      * Scans the next token of the input into a boolean value and returns
1900      * that value. This method will throw {@code InputMismatchException}
1901      * if the next token cannot be translated into a valid boolean value.
1902      * If the match is successful, the scanner advances past the input that
1903      * matched.
1904      *
1905      * @return the boolean scanned from the input
1906      * @throws InputMismatchException if the next token is not a valid boolean
1907      * @throws NoSuchElementException if input is exhausted
1908      * @throws IllegalStateException if this scanner is closed
1909      */
nextBoolean()1910     public boolean nextBoolean()  {
1911         clearCaches();
1912         return Boolean.parseBoolean(next(boolPattern()));
1913     }
1914 
1915     /**
1916      * Returns true if the next token in this scanner's input can be
1917      * interpreted as a byte value in the default radix using the
1918      * {@link #nextByte} method. The scanner does not advance past any input.
1919      *
1920      * @return true if and only if this scanner's next token is a valid
1921      *         byte value
1922      * @throws IllegalStateException if this scanner is closed
1923      */
hasNextByte()1924     public boolean hasNextByte() {
1925         return hasNextByte(defaultRadix);
1926     }
1927 
1928     /**
1929      * Returns true if the next token in this scanner's input can be
1930      * interpreted as a byte value in the specified radix using the
1931      * {@link #nextByte} method. The scanner does not advance past any input.
1932      *
1933      * <p>If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX}
1934      * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an
1935      * {@code IllegalArgumentException} is thrown.
1936      *
1937      * @param radix the radix used to interpret the token as a byte value
1938      * @return true if and only if this scanner's next token is a valid
1939      *         byte value
1940      * @throws IllegalStateException if this scanner is closed
1941      * @throws IllegalArgumentException if the radix is out of range
1942      */
hasNextByte(int radix)1943     public boolean hasNextByte(int radix) {
1944         setRadix(radix);
1945         boolean result = hasNext(integerPattern());
1946         if (result) { // Cache it
1947             try {
1948                 String s = (matcher.group(SIMPLE_GROUP_INDEX) == null) ?
1949                     processIntegerToken(hasNextResult) :
1950                     hasNextResult;
1951                 typeCache = Byte.parseByte(s, radix);
1952             } catch (NumberFormatException nfe) {
1953                 result = false;
1954             }
1955         }
1956         return result;
1957     }
1958 
1959     /**
1960      * Scans the next token of the input as a {@code byte}.
1961      *
1962      * <p> An invocation of this method of the form
1963      * {@code nextByte()} behaves in exactly the same way as the
1964      * invocation {@code nextByte(radix)}, where {@code radix}
1965      * is the default radix of this scanner.
1966      *
1967      * @return the {@code byte} scanned from the input
1968      * @throws InputMismatchException
1969      *         if the next token does not match the <i>Integer</i>
1970      *         regular expression, or is out of range
1971      * @throws NoSuchElementException if input is exhausted
1972      * @throws IllegalStateException if this scanner is closed
1973      */
nextByte()1974     public byte nextByte() {
1975          return nextByte(defaultRadix);
1976     }
1977 
1978     /**
1979      * Scans the next token of the input as a {@code byte}.
1980      * This method will throw {@code InputMismatchException}
1981      * if the next token cannot be translated into a valid byte value as
1982      * described below. If the translation is successful, the scanner advances
1983      * past the input that matched.
1984      *
1985      * <p> If the next token matches the <a
1986      * href="#Integer-regex"><i>Integer</i></a> regular expression defined
1987      * above then the token is converted into a {@code byte} value as if by
1988      * removing all locale specific prefixes, group separators, and locale
1989      * specific suffixes, then mapping non-ASCII digits into ASCII
1990      * digits via {@link Character#digit Character.digit}, prepending a
1991      * negative sign (-) if the locale specific negative prefixes and suffixes
1992      * were present, and passing the resulting string to
1993      * {@link Byte#parseByte(String, int) Byte.parseByte} with the
1994      * specified radix.
1995      *
1996      * <p>If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX}
1997      * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an
1998      * {@code IllegalArgumentException} is thrown.
1999      *
2000      * @param radix the radix used to interpret the token as a byte value
2001      * @return the {@code byte} scanned from the input
2002      * @throws InputMismatchException
2003      *         if the next token does not match the <i>Integer</i>
2004      *         regular expression, or is out of range
2005      * @throws NoSuchElementException if input is exhausted
2006      * @throws IllegalStateException if this scanner is closed
2007      * @throws IllegalArgumentException if the radix is out of range
2008      */
nextByte(int radix)2009     public byte nextByte(int radix) {
2010         // Check cached result
2011         if ((typeCache != null) && (typeCache instanceof Byte)
2012             && this.radix == radix) {
2013             byte val = ((Byte)typeCache).byteValue();
2014             useTypeCache();
2015             return val;
2016         }
2017         setRadix(radix);
2018         clearCaches();
2019         // Search for next byte
2020         try {
2021             String s = next(integerPattern());
2022             if (matcher.group(SIMPLE_GROUP_INDEX) == null)
2023                 s = processIntegerToken(s);
2024             return Byte.parseByte(s, radix);
2025         } catch (NumberFormatException nfe) {
2026             position = matcher.start(); // don't skip bad token
2027             throw new InputMismatchException(nfe.getMessage());
2028         }
2029     }
2030 
2031     /**
2032      * Returns true if the next token in this scanner's input can be
2033      * interpreted as a short value in the default radix using the
2034      * {@link #nextShort} method. The scanner does not advance past any input.
2035      *
2036      * @return true if and only if this scanner's next token is a valid
2037      *         short value in the default radix
2038      * @throws IllegalStateException if this scanner is closed
2039      */
hasNextShort()2040     public boolean hasNextShort() {
2041         return hasNextShort(defaultRadix);
2042     }
2043 
2044     /**
2045      * Returns true if the next token in this scanner's input can be
2046      * interpreted as a short value in the specified radix using the
2047      * {@link #nextShort} method. The scanner does not advance past any input.
2048      *
2049      * <p>If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX}
2050      * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an
2051      * {@code IllegalArgumentException} is thrown.
2052      *
2053      * @param radix the radix used to interpret the token as a short value
2054      * @return true if and only if this scanner's next token is a valid
2055      *         short value in the specified radix
2056      * @throws IllegalStateException if this scanner is closed
2057      * @throws IllegalArgumentException if the radix is out of range
2058      */
hasNextShort(int radix)2059     public boolean hasNextShort(int radix) {
2060         setRadix(radix);
2061         boolean result = hasNext(integerPattern());
2062         if (result) { // Cache it
2063             try {
2064                 String s = (matcher.group(SIMPLE_GROUP_INDEX) == null) ?
2065                     processIntegerToken(hasNextResult) :
2066                     hasNextResult;
2067                 typeCache = Short.parseShort(s, radix);
2068             } catch (NumberFormatException nfe) {
2069                 result = false;
2070             }
2071         }
2072         return result;
2073     }
2074 
2075     /**
2076      * Scans the next token of the input as a {@code short}.
2077      *
2078      * <p> An invocation of this method of the form
2079      * {@code nextShort()} behaves in exactly the same way as the
2080      * invocation {@link #nextShort(int) nextShort(radix)}, where {@code radix}
2081      * is the default radix of this scanner.
2082      *
2083      * @return the {@code short} scanned from the input
2084      * @throws InputMismatchException
2085      *         if the next token does not match the <i>Integer</i>
2086      *         regular expression, or is out of range
2087      * @throws NoSuchElementException if input is exhausted
2088      * @throws IllegalStateException if this scanner is closed
2089      */
nextShort()2090     public short nextShort() {
2091         return nextShort(defaultRadix);
2092     }
2093 
2094     /**
2095      * Scans the next token of the input as a {@code short}.
2096      * This method will throw {@code InputMismatchException}
2097      * if the next token cannot be translated into a valid short value as
2098      * described below. If the translation is successful, the scanner advances
2099      * past the input that matched.
2100      *
2101      * <p> If the next token matches the <a
2102      * href="#Integer-regex"><i>Integer</i></a> regular expression defined
2103      * above then the token is converted into a {@code short} value as if by
2104      * removing all locale specific prefixes, group separators, and locale
2105      * specific suffixes, then mapping non-ASCII digits into ASCII
2106      * digits via {@link Character#digit Character.digit}, prepending a
2107      * negative sign (-) if the locale specific negative prefixes and suffixes
2108      * were present, and passing the resulting string to
2109      * {@link Short#parseShort(String, int) Short.parseShort} with the
2110      * specified radix.
2111      *
2112      * <p>If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX}
2113      * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an
2114      * {@code IllegalArgumentException} is thrown.
2115      *
2116      * @param radix the radix used to interpret the token as a short value
2117      * @return the {@code short} scanned from the input
2118      * @throws InputMismatchException
2119      *         if the next token does not match the <i>Integer</i>
2120      *         regular expression, or is out of range
2121      * @throws NoSuchElementException if input is exhausted
2122      * @throws IllegalStateException if this scanner is closed
2123      * @throws IllegalArgumentException if the radix is out of range
2124      */
nextShort(int radix)2125     public short nextShort(int radix) {
2126         // Check cached result
2127         if ((typeCache != null) && (typeCache instanceof Short)
2128             && this.radix == radix) {
2129             short val = ((Short)typeCache).shortValue();
2130             useTypeCache();
2131             return val;
2132         }
2133         setRadix(radix);
2134         clearCaches();
2135         // Search for next short
2136         try {
2137             String s = next(integerPattern());
2138             if (matcher.group(SIMPLE_GROUP_INDEX) == null)
2139                 s = processIntegerToken(s);
2140             return Short.parseShort(s, radix);
2141         } catch (NumberFormatException nfe) {
2142             position = matcher.start(); // don't skip bad token
2143             throw new InputMismatchException(nfe.getMessage());
2144         }
2145     }
2146 
2147     /**
2148      * Returns true if the next token in this scanner's input can be
2149      * interpreted as an int value in the default radix using the
2150      * {@link #nextInt} method. The scanner does not advance past any input.
2151      *
2152      * @return true if and only if this scanner's next token is a valid
2153      *         int value
2154      * @throws IllegalStateException if this scanner is closed
2155      */
hasNextInt()2156     public boolean hasNextInt() {
2157         return hasNextInt(defaultRadix);
2158     }
2159 
2160     /**
2161      * Returns true if the next token in this scanner's input can be
2162      * interpreted as an int value in the specified radix using the
2163      * {@link #nextInt} method. The scanner does not advance past any input.
2164      *
2165      * <p>If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX}
2166      * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an
2167      * {@code IllegalArgumentException} is thrown.
2168      *
2169      * @param radix the radix used to interpret the token as an int value
2170      * @return true if and only if this scanner's next token is a valid
2171      *         int value
2172      * @throws IllegalStateException if this scanner is closed
2173      * @throws IllegalArgumentException if the radix is out of range
2174      */
hasNextInt(int radix)2175     public boolean hasNextInt(int radix) {
2176         setRadix(radix);
2177         boolean result = hasNext(integerPattern());
2178         if (result) { // Cache it
2179             try {
2180                 String s = (matcher.group(SIMPLE_GROUP_INDEX) == null) ?
2181                     processIntegerToken(hasNextResult) :
2182                     hasNextResult;
2183                 typeCache = Integer.parseInt(s, radix);
2184             } catch (NumberFormatException nfe) {
2185                 result = false;
2186             }
2187         }
2188         return result;
2189     }
2190 
2191     /**
2192      * The integer token must be stripped of prefixes, group separators,
2193      * and suffixes, non ascii digits must be converted into ascii digits
2194      * before parse will accept it.
2195      */
processIntegerToken(String token)2196     private String processIntegerToken(String token) {
2197         String result = token.replaceAll(""+groupSeparator, "");
2198         boolean isNegative = false;
2199         int preLen = negativePrefix.length();
2200         if ((preLen > 0) && result.startsWith(negativePrefix)) {
2201             isNegative = true;
2202             result = result.substring(preLen);
2203         }
2204         int sufLen = negativeSuffix.length();
2205         if ((sufLen > 0) && result.endsWith(negativeSuffix)) {
2206             isNegative = true;
2207             result = result.substring(result.length() - sufLen,
2208                                       result.length());
2209         }
2210         if (isNegative)
2211             result = "-" + result;
2212         return result;
2213     }
2214 
2215     /**
2216      * Scans the next token of the input as an {@code int}.
2217      *
2218      * <p> An invocation of this method of the form
2219      * {@code nextInt()} behaves in exactly the same way as the
2220      * invocation {@code nextInt(radix)}, where {@code radix}
2221      * is the default radix of this scanner.
2222      *
2223      * @return the {@code int} scanned from the input
2224      * @throws InputMismatchException
2225      *         if the next token does not match the <i>Integer</i>
2226      *         regular expression, or is out of range
2227      * @throws NoSuchElementException if input is exhausted
2228      * @throws IllegalStateException if this scanner is closed
2229      */
nextInt()2230     public int nextInt() {
2231         return nextInt(defaultRadix);
2232     }
2233 
2234     /**
2235      * Scans the next token of the input as an {@code int}.
2236      * This method will throw {@code InputMismatchException}
2237      * if the next token cannot be translated into a valid int value as
2238      * described below. If the translation is successful, the scanner advances
2239      * past the input that matched.
2240      *
2241      * <p> If the next token matches the <a
2242      * href="#Integer-regex"><i>Integer</i></a> regular expression defined
2243      * above then the token is converted into an {@code int} value as if by
2244      * removing all locale specific prefixes, group separators, and locale
2245      * specific suffixes, then mapping non-ASCII digits into ASCII
2246      * digits via {@link Character#digit Character.digit}, prepending a
2247      * negative sign (-) if the locale specific negative prefixes and suffixes
2248      * were present, and passing the resulting string to
2249      * {@link Integer#parseInt(String, int) Integer.parseInt} with the
2250      * specified radix.
2251      *
2252      * <p>If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX}
2253      * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an
2254      * {@code IllegalArgumentException} is thrown.
2255      *
2256      * @param radix the radix used to interpret the token as an int value
2257      * @return the {@code int} scanned from the input
2258      * @throws InputMismatchException
2259      *         if the next token does not match the <i>Integer</i>
2260      *         regular expression, or is out of range
2261      * @throws NoSuchElementException if input is exhausted
2262      * @throws IllegalStateException if this scanner is closed
2263      * @throws IllegalArgumentException if the radix is out of range
2264      */
nextInt(int radix)2265     public int nextInt(int radix) {
2266         // Check cached result
2267         if ((typeCache != null) && (typeCache instanceof Integer)
2268             && this.radix == radix) {
2269             int val = ((Integer)typeCache).intValue();
2270             useTypeCache();
2271             return val;
2272         }
2273         setRadix(radix);
2274         clearCaches();
2275         // Search for next int
2276         try {
2277             String s = next(integerPattern());
2278             if (matcher.group(SIMPLE_GROUP_INDEX) == null)
2279                 s = processIntegerToken(s);
2280             return Integer.parseInt(s, radix);
2281         } catch (NumberFormatException nfe) {
2282             position = matcher.start(); // don't skip bad token
2283             throw new InputMismatchException(nfe.getMessage());
2284         }
2285     }
2286 
2287     /**
2288      * Returns true if the next token in this scanner's input can be
2289      * interpreted as a long value in the default radix using the
2290      * {@link #nextLong} method. The scanner does not advance past any input.
2291      *
2292      * @return true if and only if this scanner's next token is a valid
2293      *         long value
2294      * @throws IllegalStateException if this scanner is closed
2295      */
hasNextLong()2296     public boolean hasNextLong() {
2297         return hasNextLong(defaultRadix);
2298     }
2299 
2300     /**
2301      * Returns true if the next token in this scanner's input can be
2302      * interpreted as a long value in the specified radix using the
2303      * {@link #nextLong} method. The scanner does not advance past any input.
2304      *
2305      * <p>If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX}
2306      * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an
2307      * {@code IllegalArgumentException} is thrown.
2308      *
2309      * @param radix the radix used to interpret the token as a long value
2310      * @return true if and only if this scanner's next token is a valid
2311      *         long value
2312      * @throws IllegalStateException if this scanner is closed
2313      * @throws IllegalArgumentException if the radix is out of range
2314      */
hasNextLong(int radix)2315     public boolean hasNextLong(int radix) {
2316         setRadix(radix);
2317         boolean result = hasNext(integerPattern());
2318         if (result) { // Cache it
2319             try {
2320                 String s = (matcher.group(SIMPLE_GROUP_INDEX) == null) ?
2321                     processIntegerToken(hasNextResult) :
2322                     hasNextResult;
2323                 typeCache = Long.parseLong(s, radix);
2324             } catch (NumberFormatException nfe) {
2325                 result = false;
2326             }
2327         }
2328         return result;
2329     }
2330 
2331     /**
2332      * Scans the next token of the input as a {@code long}.
2333      *
2334      * <p> An invocation of this method of the form
2335      * {@code nextLong()} behaves in exactly the same way as the
2336      * invocation {@code nextLong(radix)}, where {@code radix}
2337      * is the default radix of this scanner.
2338      *
2339      * @return the {@code long} scanned from the input
2340      * @throws InputMismatchException
2341      *         if the next token does not match the <i>Integer</i>
2342      *         regular expression, or is out of range
2343      * @throws NoSuchElementException if input is exhausted
2344      * @throws IllegalStateException if this scanner is closed
2345      */
nextLong()2346     public long nextLong() {
2347         return nextLong(defaultRadix);
2348     }
2349 
2350     /**
2351      * Scans the next token of the input as a {@code long}.
2352      * This method will throw {@code InputMismatchException}
2353      * if the next token cannot be translated into a valid long value as
2354      * described below. If the translation is successful, the scanner advances
2355      * past the input that matched.
2356      *
2357      * <p> If the next token matches the <a
2358      * href="#Integer-regex"><i>Integer</i></a> regular expression defined
2359      * above then the token is converted into a {@code long} value as if by
2360      * removing all locale specific prefixes, group separators, and locale
2361      * specific suffixes, then mapping non-ASCII digits into ASCII
2362      * digits via {@link Character#digit Character.digit}, prepending a
2363      * negative sign (-) if the locale specific negative prefixes and suffixes
2364      * were present, and passing the resulting string to
2365      * {@link Long#parseLong(String, int) Long.parseLong} with the
2366      * specified radix.
2367      *
2368      * <p>If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX}
2369      * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an
2370      * {@code IllegalArgumentException} is thrown.
2371      *
2372      * @param radix the radix used to interpret the token as an int value
2373      * @return the {@code long} scanned from the input
2374      * @throws InputMismatchException
2375      *         if the next token does not match the <i>Integer</i>
2376      *         regular expression, or is out of range
2377      * @throws NoSuchElementException if input is exhausted
2378      * @throws IllegalStateException if this scanner is closed
2379      * @throws IllegalArgumentException if the radix is out of range
2380      */
nextLong(int radix)2381     public long nextLong(int radix) {
2382         // Check cached result
2383         if ((typeCache != null) && (typeCache instanceof Long)
2384             && this.radix == radix) {
2385             long val = ((Long)typeCache).longValue();
2386             useTypeCache();
2387             return val;
2388         }
2389         setRadix(radix);
2390         clearCaches();
2391         try {
2392             String s = next(integerPattern());
2393             if (matcher.group(SIMPLE_GROUP_INDEX) == null)
2394                 s = processIntegerToken(s);
2395             return Long.parseLong(s, radix);
2396         } catch (NumberFormatException nfe) {
2397             position = matcher.start(); // don't skip bad token
2398             throw new InputMismatchException(nfe.getMessage());
2399         }
2400     }
2401 
2402     /**
2403      * The float token must be stripped of prefixes, group separators,
2404      * and suffixes, non ascii digits must be converted into ascii digits
2405      * before parseFloat will accept it.
2406      *
2407      * If there are non-ascii digits in the token these digits must
2408      * be processed before the token is passed to parseFloat.
2409      */
processFloatToken(String token)2410     private String processFloatToken(String token) {
2411         String result = token.replaceAll(groupSeparator, "");
2412         if (!decimalSeparator.equals("\\."))
2413             result = result.replaceAll(decimalSeparator, ".");
2414         boolean isNegative = false;
2415         int preLen = negativePrefix.length();
2416         if ((preLen > 0) && result.startsWith(negativePrefix)) {
2417             isNegative = true;
2418             result = result.substring(preLen);
2419         }
2420         int sufLen = negativeSuffix.length();
2421         if ((sufLen > 0) && result.endsWith(negativeSuffix)) {
2422             isNegative = true;
2423             result = result.substring(result.length() - sufLen,
2424                                       result.length());
2425         }
2426         if (result.equals(nanString))
2427             result = "NaN";
2428         if (result.equals(infinityString))
2429             result = "Infinity";
2430         // BEGIN Android-added: Match the infinity symbol.
2431         if (result.equals("\u221E"))
2432             result = "Infinity";
2433         // END Android-added: Match the infinity symbol.
2434         if (isNegative)
2435             result = "-" + result;
2436 
2437         // Translate non-ASCII digits
2438         Matcher m = NON_ASCII_DIGIT.matcher(result);
2439         if (m.find()) {
2440             StringBuilder inASCII = new StringBuilder();
2441             for (int i=0; i<result.length(); i++) {
2442                 char nextChar = result.charAt(i);
2443                 if (Character.isDigit(nextChar)) {
2444                     int d = Character.digit(nextChar, 10);
2445                     if (d != -1)
2446                         inASCII.append(d);
2447                     else
2448                         inASCII.append(nextChar);
2449                 } else {
2450                     inASCII.append(nextChar);
2451                 }
2452             }
2453             result = inASCII.toString();
2454         }
2455 
2456         return result;
2457     }
2458 
2459     /**
2460      * Returns true if the next token in this scanner's input can be
2461      * interpreted as a float value using the {@link #nextFloat}
2462      * method. The scanner does not advance past any input.
2463      *
2464      * @return true if and only if this scanner's next token is a valid
2465      *         float value
2466      * @throws IllegalStateException if this scanner is closed
2467      */
hasNextFloat()2468     public boolean hasNextFloat() {
2469         setRadix(10);
2470         boolean result = hasNext(floatPattern());
2471         if (result) { // Cache it
2472             try {
2473                 String s = processFloatToken(hasNextResult);
2474                 typeCache = Float.valueOf(Float.parseFloat(s));
2475             } catch (NumberFormatException nfe) {
2476                 result = false;
2477             }
2478         }
2479         return result;
2480     }
2481 
2482     /**
2483      * Scans the next token of the input as a {@code float}.
2484      * This method will throw {@code InputMismatchException}
2485      * if the next token cannot be translated into a valid float value as
2486      * described below. If the translation is successful, the scanner advances
2487      * past the input that matched.
2488      *
2489      * <p> If the next token matches the <a
2490      * href="#Float-regex"><i>Float</i></a> regular expression defined above
2491      * then the token is converted into a {@code float} value as if by
2492      * removing all locale specific prefixes, group separators, and locale
2493      * specific suffixes, then mapping non-ASCII digits into ASCII
2494      * digits via {@link Character#digit Character.digit}, prepending a
2495      * negative sign (-) if the locale specific negative prefixes and suffixes
2496      * were present, and passing the resulting string to
2497      * {@link Float#parseFloat Float.parseFloat}. If the token matches
2498      * the localized NaN or infinity strings, then either "Nan" or "Infinity"
2499      * is passed to {@link Float#parseFloat(String) Float.parseFloat} as
2500      * appropriate.
2501      *
2502      * @return the {@code float} scanned from the input
2503      * @throws InputMismatchException
2504      *         if the next token does not match the <i>Float</i>
2505      *         regular expression, or is out of range
2506      * @throws NoSuchElementException if input is exhausted
2507      * @throws IllegalStateException if this scanner is closed
2508      */
nextFloat()2509     public float nextFloat() {
2510         // Check cached result
2511         if ((typeCache != null) && (typeCache instanceof Float)) {
2512             float val = ((Float)typeCache).floatValue();
2513             useTypeCache();
2514             return val;
2515         }
2516         setRadix(10);
2517         clearCaches();
2518         try {
2519             return Float.parseFloat(processFloatToken(next(floatPattern())));
2520         } catch (NumberFormatException nfe) {
2521             position = matcher.start(); // don't skip bad token
2522             throw new InputMismatchException(nfe.getMessage());
2523         }
2524     }
2525 
2526     /**
2527      * Returns true if the next token in this scanner's input can be
2528      * interpreted as a double value using the {@link #nextDouble}
2529      * method. The scanner does not advance past any input.
2530      *
2531      * @return true if and only if this scanner's next token is a valid
2532      *         double value
2533      * @throws IllegalStateException if this scanner is closed
2534      */
hasNextDouble()2535     public boolean hasNextDouble() {
2536         setRadix(10);
2537         boolean result = hasNext(floatPattern());
2538         if (result) { // Cache it
2539             try {
2540                 String s = processFloatToken(hasNextResult);
2541                 typeCache = Double.valueOf(Double.parseDouble(s));
2542             } catch (NumberFormatException nfe) {
2543                 result = false;
2544             }
2545         }
2546         return result;
2547     }
2548 
2549     /**
2550      * Scans the next token of the input as a {@code double}.
2551      * This method will throw {@code InputMismatchException}
2552      * if the next token cannot be translated into a valid double value.
2553      * If the translation is successful, the scanner advances past the input
2554      * that matched.
2555      *
2556      * <p> If the next token matches the <a
2557      * href="#Float-regex"><i>Float</i></a> regular expression defined above
2558      * then the token is converted into a {@code double} value as if by
2559      * removing all locale specific prefixes, group separators, and locale
2560      * specific suffixes, then mapping non-ASCII digits into ASCII
2561      * digits via {@link Character#digit Character.digit}, prepending a
2562      * negative sign (-) if the locale specific negative prefixes and suffixes
2563      * were present, and passing the resulting string to
2564      * {@link Double#parseDouble Double.parseDouble}. If the token matches
2565      * the localized NaN or infinity strings, then either "Nan" or "Infinity"
2566      * is passed to {@link Double#parseDouble(String) Double.parseDouble} as
2567      * appropriate.
2568      *
2569      * @return the {@code double} scanned from the input
2570      * @throws InputMismatchException
2571      *         if the next token does not match the <i>Float</i>
2572      *         regular expression, or is out of range
2573      * @throws NoSuchElementException if the input is exhausted
2574      * @throws IllegalStateException if this scanner is closed
2575      */
nextDouble()2576     public double nextDouble() {
2577         // Check cached result
2578         if ((typeCache != null) && (typeCache instanceof Double)) {
2579             double val = ((Double)typeCache).doubleValue();
2580             useTypeCache();
2581             return val;
2582         }
2583         setRadix(10);
2584         clearCaches();
2585         // Search for next float
2586         try {
2587             return Double.parseDouble(processFloatToken(next(floatPattern())));
2588         } catch (NumberFormatException nfe) {
2589             position = matcher.start(); // don't skip bad token
2590             throw new InputMismatchException(nfe.getMessage());
2591         }
2592     }
2593 
2594     // Convenience methods for scanning multi precision numbers
2595 
2596     /**
2597      * Returns true if the next token in this scanner's input can be
2598      * interpreted as a {@code BigInteger} in the default radix using the
2599      * {@link #nextBigInteger} method. The scanner does not advance past any
2600      * input.
2601      *
2602      * @return true if and only if this scanner's next token is a valid
2603      *         {@code BigInteger}
2604      * @throws IllegalStateException if this scanner is closed
2605      */
hasNextBigInteger()2606     public boolean hasNextBigInteger() {
2607         return hasNextBigInteger(defaultRadix);
2608     }
2609 
2610     /**
2611      * Returns true if the next token in this scanner's input can be
2612      * interpreted as a {@code BigInteger} in the specified radix using
2613      * the {@link #nextBigInteger} method. The scanner does not advance past
2614      * any input.
2615      *
2616      * <p>If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX}
2617      * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an
2618      * {@code IllegalArgumentException} is thrown.
2619      *
2620      * @param radix the radix used to interpret the token as an integer
2621      * @return true if and only if this scanner's next token is a valid
2622      *         {@code BigInteger}
2623      * @throws IllegalStateException if this scanner is closed
2624      * @throws IllegalArgumentException if the radix is out of range
2625      */
hasNextBigInteger(int radix)2626     public boolean hasNextBigInteger(int radix) {
2627         setRadix(radix);
2628         boolean result = hasNext(integerPattern());
2629         if (result) { // Cache it
2630             try {
2631                 String s = (matcher.group(SIMPLE_GROUP_INDEX) == null) ?
2632                     processIntegerToken(hasNextResult) :
2633                     hasNextResult;
2634                 typeCache = new BigInteger(s, radix);
2635             } catch (NumberFormatException nfe) {
2636                 result = false;
2637             }
2638         }
2639         return result;
2640     }
2641 
2642     /**
2643      * Scans the next token of the input as a {@link java.math.BigInteger
2644      * BigInteger}.
2645      *
2646      * <p> An invocation of this method of the form
2647      * {@code nextBigInteger()} behaves in exactly the same way as the
2648      * invocation {@code nextBigInteger(radix)}, where {@code radix}
2649      * is the default radix of this scanner.
2650      *
2651      * @return the {@code BigInteger} scanned from the input
2652      * @throws InputMismatchException
2653      *         if the next token does not match the <i>Integer</i>
2654      *         regular expression, or is out of range
2655      * @throws NoSuchElementException if the input is exhausted
2656      * @throws IllegalStateException if this scanner is closed
2657      */
nextBigInteger()2658     public BigInteger nextBigInteger() {
2659         return nextBigInteger(defaultRadix);
2660     }
2661 
2662     /**
2663      * Scans the next token of the input as a {@link java.math.BigInteger
2664      * BigInteger}.
2665      *
2666      * <p> If the next token matches the <a
2667      * href="#Integer-regex"><i>Integer</i></a> regular expression defined
2668      * above then the token is converted into a {@code BigInteger} value as if
2669      * by removing all group separators, mapping non-ASCII digits into ASCII
2670      * digits via the {@link Character#digit Character.digit}, and passing the
2671      * resulting string to the {@link
2672      * java.math.BigInteger#BigInteger(java.lang.String)
2673      * BigInteger(String, int)} constructor with the specified radix.
2674      *
2675      * <p>If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX}
2676      * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an
2677      * {@code IllegalArgumentException} is thrown.
2678      *
2679      * @param radix the radix used to interpret the token
2680      * @return the {@code BigInteger} scanned from the input
2681      * @throws InputMismatchException
2682      *         if the next token does not match the <i>Integer</i>
2683      *         regular expression, or is out of range
2684      * @throws NoSuchElementException if the input is exhausted
2685      * @throws IllegalStateException if this scanner is closed
2686      * @throws IllegalArgumentException if the radix is out of range
2687      */
nextBigInteger(int radix)2688     public BigInteger nextBigInteger(int radix) {
2689         // Check cached result
2690         if ((typeCache != null) && (typeCache instanceof BigInteger val)
2691             && this.radix == radix) {
2692             useTypeCache();
2693             return val;
2694         }
2695         setRadix(radix);
2696         clearCaches();
2697         // Search for next int
2698         try {
2699             String s = next(integerPattern());
2700             if (matcher.group(SIMPLE_GROUP_INDEX) == null)
2701                 s = processIntegerToken(s);
2702             return new BigInteger(s, radix);
2703         } catch (NumberFormatException nfe) {
2704             position = matcher.start(); // don't skip bad token
2705             throw new InputMismatchException(nfe.getMessage());
2706         }
2707     }
2708 
2709     /**
2710      * Returns true if the next token in this scanner's input can be
2711      * interpreted as a {@code BigDecimal} using the
2712      * {@link #nextBigDecimal} method. The scanner does not advance past any
2713      * input.
2714      *
2715      * @return true if and only if this scanner's next token is a valid
2716      *         {@code BigDecimal}
2717      * @throws IllegalStateException if this scanner is closed
2718      */
hasNextBigDecimal()2719     public boolean hasNextBigDecimal() {
2720         setRadix(10);
2721         boolean result = hasNext(decimalPattern());
2722         if (result) { // Cache it
2723             try {
2724                 String s = processFloatToken(hasNextResult);
2725                 typeCache = new BigDecimal(s);
2726             } catch (NumberFormatException nfe) {
2727                 result = false;
2728             }
2729         }
2730         return result;
2731     }
2732 
2733     /**
2734      * Scans the next token of the input as a {@link java.math.BigDecimal
2735      * BigDecimal}.
2736      *
2737      * <p> If the next token matches the <a
2738      * href="#Decimal-regex"><i>Decimal</i></a> regular expression defined
2739      * above then the token is converted into a {@code BigDecimal} value as if
2740      * by removing all group separators, mapping non-ASCII digits into ASCII
2741      * digits via the {@link Character#digit Character.digit}, and passing the
2742      * resulting string to the {@link
2743      * java.math.BigDecimal#BigDecimal(java.lang.String) BigDecimal(String)}
2744      * constructor.
2745      *
2746      * @return the {@code BigDecimal} scanned from the input
2747      * @throws InputMismatchException
2748      *         if the next token does not match the <i>Decimal</i>
2749      *         regular expression, or is out of range
2750      * @throws NoSuchElementException if the input is exhausted
2751      * @throws IllegalStateException if this scanner is closed
2752      */
nextBigDecimal()2753     public BigDecimal nextBigDecimal() {
2754         // Check cached result
2755         if ((typeCache != null) && (typeCache instanceof BigDecimal val)) {
2756             useTypeCache();
2757             return val;
2758         }
2759         setRadix(10);
2760         clearCaches();
2761         // Search for next float
2762         try {
2763             String s = processFloatToken(next(decimalPattern()));
2764             return new BigDecimal(s);
2765         } catch (NumberFormatException nfe) {
2766             position = matcher.start(); // don't skip bad token
2767             throw new InputMismatchException(nfe.getMessage());
2768         }
2769     }
2770 
2771     /**
2772      * Resets this scanner.
2773      *
2774      * <p> Resetting a scanner discards all of its explicit state
2775      * information which may have been changed by invocations of
2776      * {@link #useDelimiter useDelimiter()},
2777      * {@link #useLocale useLocale()}, or
2778      * {@link #useRadix useRadix()}.
2779      *
2780      * <p> An invocation of this method of the form
2781      * {@code scanner.reset()} behaves in exactly the same way as the
2782      * invocation
2783      *
2784      * <blockquote><pre>{@code
2785      *   scanner.useDelimiter("\\p{javaWhitespace}+")
2786      *          .useLocale(Locale.getDefault(Locale.Category.FORMAT))
2787      *          .useRadix(10);
2788      * }</pre></blockquote>
2789      *
2790      * @return this scanner
2791      *
2792      * @since 1.6
2793      */
reset()2794     public Scanner reset() {
2795         delimPattern = WHITESPACE_PATTERN;
2796         useLocale(Locale.getDefault(Locale.Category.FORMAT));
2797         useRadix(10);
2798         clearCaches();
2799         modCount++;
2800         return this;
2801     }
2802 
2803     /**
2804      * Returns a stream of delimiter-separated tokens from this scanner. The
2805      * stream contains the same tokens that would be returned, starting from
2806      * this scanner's current state, by calling the {@link #next} method
2807      * repeatedly until the {@link #hasNext} method returns false.
2808      *
2809      * <p>The resulting stream is sequential and ordered. All stream elements are
2810      * non-null.
2811      *
2812      * <p>Scanning starts upon initiation of the terminal stream operation, using the
2813      * current state of this scanner. Subsequent calls to any methods on this scanner
2814      * other than {@link #close} and {@link #ioException} may return undefined results
2815      * or may cause undefined effects on the returned stream. The returned stream's source
2816      * {@code Spliterator} is <em>fail-fast</em> and will, on a best-effort basis, throw a
2817      * {@link java.util.ConcurrentModificationException} if any such calls are detected
2818      * during stream pipeline execution.
2819      *
2820      * <p>After stream pipeline execution completes, this scanner is left in an indeterminate
2821      * state and cannot be reused.
2822      *
2823      * <p>If this scanner contains a resource that must be released, this scanner
2824      * should be closed, either by calling its {@link #close} method, or by
2825      * closing the returned stream. Closing the stream will close the underlying scanner.
2826      * {@code IllegalStateException} is thrown if the scanner has been closed when this
2827      * method is called, or if this scanner is closed during stream pipeline execution.
2828      *
2829      * <p>This method might block waiting for more input.
2830      *
2831      * @apiNote
2832      * For example, the following code will create a list of
2833      * comma-delimited tokens from a string:
2834      *
2835      * <pre>{@code
2836      * List<String> result = new Scanner("abc,def,,ghi")
2837      *     .useDelimiter(",")
2838      *     .tokens()
2839      *     .collect(Collectors.toList());
2840      * }</pre>
2841      *
2842      * <p>The resulting list would contain {@code "abc"}, {@code "def"},
2843      * the empty string, and {@code "ghi"}.
2844      *
2845      * @return a sequential stream of token strings
2846      * @throws IllegalStateException if this scanner is closed
2847      * @since 9
2848      */
tokens()2849     public Stream<String> tokens() {
2850         ensureOpen();
2851         Stream<String> stream = StreamSupport.stream(new TokenSpliterator(), false);
2852         return stream.onClose(this::close);
2853     }
2854 
2855     class TokenSpliterator extends Spliterators.AbstractSpliterator<String> {
2856         int expectedCount = -1;
2857 
TokenSpliterator()2858         TokenSpliterator() {
2859             super(Long.MAX_VALUE,
2860                   Spliterator.IMMUTABLE | Spliterator.NONNULL | Spliterator.ORDERED);
2861         }
2862 
2863         @Override
tryAdvance(Consumer<? super String> cons)2864         public boolean tryAdvance(Consumer<? super String> cons) {
2865             if (expectedCount >= 0 && expectedCount != modCount) {
2866                 throw new ConcurrentModificationException();
2867             }
2868 
2869             if (hasNext()) {
2870                 String token = next();
2871                 expectedCount = modCount;
2872                 cons.accept(token);
2873                 if (expectedCount != modCount) {
2874                     throw new ConcurrentModificationException();
2875                 }
2876                 return true;
2877             } else {
2878                 expectedCount = modCount;
2879                 return false;
2880             }
2881         }
2882     }
2883 
2884     /**
2885      * Returns a stream of match results from this scanner. The stream
2886      * contains the same results in the same order that would be returned by
2887      * calling {@code findWithinHorizon(pattern, 0)} and then {@link #match}
2888      * successively as long as {@link #findWithinHorizon findWithinHorizon()}
2889      * finds matches.
2890      *
2891      * <p>The resulting stream is sequential and ordered. All stream elements are
2892      * non-null.
2893      *
2894      * <p>Scanning starts upon initiation of the terminal stream operation, using the
2895      * current state of this scanner. Subsequent calls to any methods on this scanner
2896      * other than {@link #close} and {@link #ioException} may return undefined results
2897      * or may cause undefined effects on the returned stream. The returned stream's source
2898      * {@code Spliterator} is <em>fail-fast</em> and will, on a best-effort basis, throw a
2899      * {@link java.util.ConcurrentModificationException} if any such calls are detected
2900      * during stream pipeline execution.
2901      *
2902      * <p>After stream pipeline execution completes, this scanner is left in an indeterminate
2903      * state and cannot be reused.
2904      *
2905      * <p>If this scanner contains a resource that must be released, this scanner
2906      * should be closed, either by calling its {@link #close} method, or by
2907      * closing the returned stream. Closing the stream will close the underlying scanner.
2908      * {@code IllegalStateException} is thrown if the scanner has been closed when this
2909      * method is called, or if this scanner is closed during stream pipeline execution.
2910      *
2911      * <p>As with the {@link #findWithinHorizon findWithinHorizon()} methods, this method
2912      * might block waiting for additional input, and it might buffer an unbounded amount of
2913      * input searching for a match.
2914      *
2915      * @apiNote
2916      * For example, the following code will read a file and return a list
2917      * of all sequences of characters consisting of seven or more Latin capital
2918      * letters:
2919      *
2920      * <pre>{@code
2921      * try (Scanner sc = new Scanner(Path.of("input.txt"))) {
2922      *     Pattern pat = Pattern.compile("[A-Z]{7,}");
2923      *     List<String> capWords = sc.findAll(pat)
2924      *                               .map(MatchResult::group)
2925      *                               .collect(Collectors.toList());
2926      * }
2927      * }</pre>
2928      *
2929      * @param pattern the pattern to be matched
2930      * @return a sequential stream of match results
2931      * @throws NullPointerException if pattern is null
2932      * @throws IllegalStateException if this scanner is closed
2933      * @since 9
2934      */
findAll(Pattern pattern)2935     public Stream<MatchResult> findAll(Pattern pattern) {
2936         Objects.requireNonNull(pattern);
2937         ensureOpen();
2938         Stream<MatchResult> stream = StreamSupport.stream(new FindSpliterator(pattern), false);
2939         return stream.onClose(this::close);
2940     }
2941 
2942     /**
2943      * Returns a stream of match results that match the provided pattern string.
2944      * The effect is equivalent to the following code:
2945      *
2946      * <pre>{@code
2947      *     scanner.findAll(Pattern.compile(patString))
2948      * }</pre>
2949      *
2950      * @param patString the pattern string
2951      * @return a sequential stream of match results
2952      * @throws NullPointerException if patString is null
2953      * @throws IllegalStateException if this scanner is closed
2954      * @throws PatternSyntaxException if the regular expression's syntax is invalid
2955      * @since 9
2956      * @see java.util.regex.Pattern
2957      */
findAll(String patString)2958     public Stream<MatchResult> findAll(String patString) {
2959         Objects.requireNonNull(patString);
2960         ensureOpen();
2961         return findAll(patternCache.forName(patString));
2962     }
2963 
2964     class FindSpliterator extends Spliterators.AbstractSpliterator<MatchResult> {
2965         final Pattern pattern;
2966         int expectedCount = -1;
2967         private boolean advance = false; // true if we need to auto-advance
2968 
FindSpliterator(Pattern pattern)2969         FindSpliterator(Pattern pattern) {
2970             super(Long.MAX_VALUE,
2971                   Spliterator.IMMUTABLE | Spliterator.NONNULL | Spliterator.ORDERED);
2972             this.pattern = pattern;
2973         }
2974 
2975         @Override
tryAdvance(Consumer<? super MatchResult> cons)2976         public boolean tryAdvance(Consumer<? super MatchResult> cons) {
2977             ensureOpen();
2978             if (expectedCount >= 0) {
2979                 if (expectedCount != modCount) {
2980                     throw new ConcurrentModificationException();
2981                 }
2982             } else {
2983                 // init
2984                 matchValid = false;
2985                 matcher.usePattern(pattern);
2986                 expectedCount = modCount;
2987             }
2988 
2989             while (true) {
2990                 // assert expectedCount == modCount
2991                 if (nextInBuffer()) { // doesn't increment modCount
2992                     cons.accept(matcher.toMatchResult());
2993                     if (expectedCount != modCount) {
2994                         throw new ConcurrentModificationException();
2995                     }
2996                     return true;
2997                 }
2998                 if (needInput)
2999                     readInput(); // doesn't increment modCount
3000                 else
3001                     return false; // reached end of input
3002             }
3003         }
3004 
3005         // reimplementation of findPatternInBuffer with auto-advance on zero-length matches
nextInBuffer()3006         private boolean nextInBuffer() {
3007             if (advance) {
3008                 if (position + 1 > buf.limit()) {
3009                     if (!sourceClosed)
3010                         needInput = true;
3011                     return false;
3012                 }
3013                 position++;
3014                 advance = false;
3015             }
3016             matcher.region(position, buf.limit());
3017             if (matcher.find() && (!matcher.hitEnd() || sourceClosed)) {
3018                  // Did not hit end, or hit real end
3019                  position = matcher.end();
3020                  advance = matcher.start() == position;
3021                  return true;
3022             }
3023             if (!sourceClosed)
3024                 needInput = true;
3025             return false;
3026         }
3027     }
3028 
3029     /** Small LRU cache of Patterns. */
3030     private static class PatternLRUCache {
3031 
3032         private Pattern[] oa = null;
3033         private final int size;
3034 
PatternLRUCache(int size)3035         PatternLRUCache(int size) {
3036             this.size = size;
3037         }
3038 
hasName(Pattern p, String s)3039         boolean hasName(Pattern p, String s) {
3040             return p.pattern().equals(s);
3041         }
3042 
moveToFront(Object[] oa, int i)3043         void moveToFront(Object[] oa, int i) {
3044             Object ob = oa[i];
3045             for (int j = i; j > 0; j--)
3046                 oa[j] = oa[j - 1];
3047             oa[0] = ob;
3048         }
3049 
forName(String name)3050         Pattern forName(String name) {
3051             if (oa == null) {
3052                 Pattern[] temp = new Pattern[size];
3053                 oa = temp;
3054             } else {
3055                 for (int i = 0; i < oa.length; i++) {
3056                     Pattern ob = oa[i];
3057                     if (ob == null)
3058                         continue;
3059                     if (hasName(ob, name)) {
3060                         if (i > 0)
3061                             moveToFront(oa, i);
3062                         return ob;
3063                     }
3064                 }
3065             }
3066 
3067             // Create a new object
3068             Pattern ob = Pattern.compile(name);
3069             oa[oa.length - 1] = ob;
3070             moveToFront(oa, oa.length - 1);
3071             return ob;
3072         }
3073     }
3074 }
3075