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