1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package java.util;
17 
18 import java.io.Closeable;
19 import java.io.File;
20 import java.io.FileInputStream;
21 import java.io.FileNotFoundException;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.InputStreamReader;
25 import java.io.StringReader;
26 import java.io.UnsupportedEncodingException;
27 import java.math.BigDecimal;
28 import java.math.BigInteger;
29 import java.nio.CharBuffer;
30 import java.nio.channels.Channels;
31 import java.nio.channels.ReadableByteChannel;
32 import java.nio.charset.Charset;
33 import java.text.DecimalFormat;
34 import java.text.DecimalFormatSymbols;
35 import java.text.NumberFormat;
36 import java.util.regex.MatchResult;
37 import java.util.regex.Matcher;
38 import java.util.regex.Pattern;
39 import libcore.io.IoUtils;
40 
41 /**
42  * A parser that parses a text string of primitive types and strings with the
43  * help of regular expressions. This class is not as useful as it might seem.
44  * It's very inefficient for communicating between machines; you should use JSON,
45  * protobufs, or even XML for that. Very simple uses might get away with {@link String#split}.
46  * For input from humans, the use of locale-specific regular expressions make it not only
47  * expensive but also somewhat unpredictable.
48  *
49  * <p>This class supports localized numbers and various
50  * radixes. The input is broken into tokens by the delimiter pattern, which is
51  * {@code \\p{javaWhitespace}} by default.
52  *
53  * <p>Example:
54  * <pre>
55  * Scanner s = new Scanner("1A true");
56  * assertEquals(26, s.nextInt(16));
57  * assertEquals(true, s.nextBoolean());
58  * </pre>
59  *
60  * <p>The {@code Scanner} class is not thread-safe.
61  */
62 public final class Scanner implements Closeable, Iterator<String> {
63 
64     private static final String NL = "\n|\r\n|\r|\u0085|\u2028|\u2029";
65 
66     // Default delimiting pattern.
67     private static final Pattern DEFAULT_DELIMITER = Pattern.compile("\\p{javaWhitespace}+");
68 
69     // The boolean's pattern.
70     private static final Pattern BOOLEAN_PATTERN = Pattern.compile("true|false", Pattern.CASE_INSENSITIVE);
71 
72     // Pattern used to recognize line terminator.
73     private static final Pattern LINE_TERMINATOR = Pattern.compile(NL);
74 
75     // Pattern used to recognize multiple line terminators.
76     private static final Pattern MULTI_LINE_TERMINATOR = Pattern.compile("(" + NL + ")+");
77 
78     // Pattern used to recognize a line with a line terminator.
79     private static final Pattern LINE_PATTERN = Pattern.compile(".*(" + NL + ")|.+$");
80 
81     // The pattern matches anything.
82     private static final Pattern ANY_PATTERN = Pattern.compile("(?s).*");
83 
84     private static final int DEFAULT_RADIX = 10;
85 
86     // The input source of scanner.
87     private Readable input;
88 
89     private CharBuffer buffer = CharBuffer.allocate(1024);
90 
91     private Pattern delimiter = DEFAULT_DELIMITER;
92 
93     private Matcher matcher;
94 
95     private int currentRadix = DEFAULT_RADIX;
96 
97     private Locale locale = Locale.getDefault();
98 
99     // The position where find begins.
100     private int findStartIndex = 0;
101 
102     // The last find start position.
103     private int preStartIndex = findStartIndex;
104 
105     // The length of the buffer.
106     private int bufferLength = 0;
107 
108     // Record the status of this scanner. True if the scanner is closed.
109     private boolean closed = false;
110 
111     private IOException lastIOException;
112 
113     private boolean matchSuccessful = false;
114 
115     private DecimalFormat decimalFormat;
116 
117     // Records whether the underlying readable has more input.
118     private boolean inputExhausted = false;
119 
120     private Object cachedNextValue = null;
121     private int cachedNextIndex = -1;
122 
123     private Pattern cachedFloatPattern = null;
124 
125     private int cachedIntegerPatternRadix = -1;
126     private Pattern cachedIntegerPattern = null;
127 
128     /**
129      * Creates a {@code Scanner} with the specified {@code File} as input. The default charset
130      * is applied when reading the file.
131      *
132      * @param src
133      *            the file to be scanned.
134      * @throws FileNotFoundException
135      *             if the specified file does not exist.
136      */
Scanner(File src)137     public Scanner(File src) throws FileNotFoundException {
138         this(src, Charset.defaultCharset().name());
139     }
140 
141     /**
142      * Creates a {@code Scanner} with the specified {@code File} as input. The specified charset
143      * is applied when reading the file.
144      *
145      * @param src
146      *            the file to be scanned.
147      * @param charsetName
148      *            the name of the encoding type of the file.
149      * @throws FileNotFoundException
150      *             if the specified file does not exist.
151      * @throws IllegalArgumentException
152      *             if the specified coding does not exist.
153      */
Scanner(File src, String charsetName)154     public Scanner(File src, String charsetName) throws FileNotFoundException {
155         if (src == null) {
156             throw new NullPointerException("src == null");
157         }
158         FileInputStream fis = new FileInputStream(src);
159         if (charsetName == null) {
160             throw new IllegalArgumentException("charsetName == null");
161         }
162 
163         InputStreamReader streamReader;
164         try {
165             streamReader = new InputStreamReader(fis, charsetName);
166         } catch (UnsupportedEncodingException e) {
167             IoUtils.closeQuietly(fis);
168             throw new IllegalArgumentException(e.getMessage());
169         }
170         initialize(streamReader);
171     }
172 
173     /**
174      * Creates a {@code Scanner} on the specified string.
175      *
176      * @param src
177      *            the string to be scanned.
178      */
Scanner(String src)179     public Scanner(String src) {
180         initialize(new StringReader(src));
181     }
182 
183     /**
184      * Creates a {@code Scanner} on the specified {@code InputStream}. The default charset is
185      * applied when decoding the input.
186      *
187      * @param src
188      *            the {@code InputStream} to be scanned.
189      */
Scanner(InputStream src)190     public Scanner(InputStream src) {
191         this(src, Charset.defaultCharset().name());
192     }
193 
194     /**
195      * Creates a {@code Scanner} on the specified {@code InputStream}. The specified charset is
196      * applied when decoding the input.
197      *
198      * @param src
199      *            the {@code InputStream} to be scanned.
200      * @param charsetName
201      *            the encoding type of the {@code InputStream}.
202      * @throws IllegalArgumentException
203      *             if the specified character set is not found.
204      */
Scanner(InputStream src, String charsetName)205     public Scanner(InputStream src, String charsetName) {
206         if (src == null) {
207             throw new NullPointerException("src == null");
208         }
209 
210         InputStreamReader streamReader;
211         try {
212             streamReader = new InputStreamReader(src, charsetName);
213         } catch (UnsupportedEncodingException e) {
214             throw new IllegalArgumentException(e.getMessage());
215         }
216         initialize(streamReader);
217     }
218 
219     /**
220      * Creates a {@code Scanner} with the specified {@code Readable} as input.
221      *
222      * @param src
223      *            the {@code Readable} to be scanned.
224      */
Scanner(Readable src)225     public Scanner(Readable src) {
226         if (src == null) {
227             throw new NullPointerException("src == null");
228         }
229         initialize(src);
230     }
231 
232     /**
233      * Creates a {@code Scanner} with the specified {@code ReadableByteChannel} as
234      * input. The default charset is applied when decoding the input.
235      *
236      * @param src
237      *            the {@code ReadableByteChannel} to be scanned.
238      */
Scanner(ReadableByteChannel src)239     public Scanner(ReadableByteChannel src) {
240         this(src, Charset.defaultCharset().name());
241     }
242 
243     /**
244      * Creates a {@code Scanner} with the specified {@code ReadableByteChannel} as
245      * input. The specified charset is applied when decoding the input.
246      *
247      * @param src
248      *            the {@code ReadableByteChannel} to be scanned.
249      * @param charsetName
250      *            the encoding type of the content.
251      * @throws IllegalArgumentException
252      *             if the specified character set is not found.
253      */
Scanner(ReadableByteChannel src, String charsetName)254     public Scanner(ReadableByteChannel src, String charsetName) {
255         if (src == null) {
256             throw new NullPointerException("src == null");
257         }
258         if (charsetName == null) {
259             throw new IllegalArgumentException("charsetName == null");
260         }
261         initialize(Channels.newReader(src, charsetName));
262     }
263 
initialize(Readable input)264     private void initialize(Readable input) {
265         this.input = input;
266         matcher = delimiter.matcher("");
267         matcher.useTransparentBounds(true);
268         matcher.useAnchoringBounds(false);
269     }
270 
271     /**
272      * Closes this {@code Scanner} and the underlying input if the input implements
273      * {@code Closeable}. If the {@code Scanner} has been closed, this method will have
274      * no effect. Any scanning operation called after calling this method will throw
275      * an {@code IllegalStateException}.
276      *
277      * @see Closeable
278      */
close()279     public void close() {
280         if (closed) {
281             return;
282         }
283         if (input instanceof Closeable) {
284             try {
285                 ((Closeable) input).close();
286             } catch (IOException e) {
287                 lastIOException = e;
288             }
289         }
290         closed = true;
291     }
292 
293     /**
294      * Returns the delimiter {@code Pattern} in use by this {@code Scanner}.
295      *
296      * @return the delimiter {@code Pattern} in use by this {@code Scanner}.
297      */
delimiter()298     public Pattern delimiter() {
299         return delimiter;
300     }
301 
302     /**
303      * Tries to find the pattern in the input. Delimiters are ignored. If the
304      * pattern is found before line terminator, the matched string will be
305      * returned, and the {@code Scanner} will advance to the end of the matched string.
306      * Otherwise, {@code null} will be returned and the {@code Scanner} will not advance.
307      * When waiting for input, the {@code Scanner} may be blocked. All the
308      * input may be cached if no line terminator exists in the buffer.
309      *
310      * @param pattern
311      *            the pattern to find in the input.
312      * @return the matched string or {@code null} if the pattern is not found
313      *         before the next line terminator.
314      * @throws IllegalStateException
315      *             if the {@code Scanner} is closed.
316      */
findInLine(Pattern pattern)317     public String findInLine(Pattern pattern) {
318         checkOpen();
319         checkNotNull(pattern);
320         int horizonLineSeparator = 0;
321 
322         matcher.usePattern(MULTI_LINE_TERMINATOR);
323         matcher.region(findStartIndex, bufferLength);
324 
325         boolean findComplete = false;
326         int terminatorLength = 0;
327         while (!findComplete) {
328             if (matcher.find()) {
329                 horizonLineSeparator = matcher.start();
330                 terminatorLength = matcher.end() - matcher.start();
331                 findComplete = true;
332             } else {
333                 if (!inputExhausted) {
334                     readMore();
335                     resetMatcher();
336                 } else {
337                     horizonLineSeparator = bufferLength;
338                     findComplete = true;
339                 }
340             }
341         }
342 
343         matcher.usePattern(pattern);
344 
345         /*
346          * TODO The following 2 statements are used to deal with regex's bug.
347          * java.util.regex.Matcher.region(int start, int end) implementation
348          * does not have any effects when called. They will be removed once the
349          * bug is fixed.
350          */
351         int oldLimit = buffer.limit();
352         // Considering the look ahead feature, the line terminator should be involved as RI
353         buffer.limit(horizonLineSeparator + terminatorLength);
354         // ========== To deal with regex bug ====================
355 
356         // Considering the look ahead feature, the line terminator should be involved as RI
357         matcher.region(findStartIndex, horizonLineSeparator + terminatorLength);
358         if (matcher.find()) {
359             // The scanner advances past the input that matched
360             findStartIndex = matcher.end();
361             // If the matched pattern is immediately followed by line
362             // terminator.
363             if (horizonLineSeparator == matcher.end()) {
364                 findStartIndex += terminatorLength;
365             }
366             // the line terminator itself should not be a part of
367             // the match result according to the Spec
368             if (horizonLineSeparator != bufferLength
369                     && (horizonLineSeparator + terminatorLength == matcher
370                             .end())) {
371                 // ========== To deal with regex bug ====================
372                 buffer.limit(oldLimit);
373                 // ========== To deal with regex bug ====================
374 
375                 matchSuccessful = false;
376                 return null;
377             }
378             matchSuccessful = true;
379 
380             // ========== To deal with regex bug ====================
381             buffer.limit(oldLimit);
382             // ========== To deal with regex bug ====================
383 
384             return matcher.group();
385         }
386 
387         // ========== To deal with regex bug ====================
388         buffer.limit(oldLimit);
389         // ========== To deal with regex bug ====================
390 
391         matchSuccessful = false;
392         return null;
393     }
394 
395     /**
396      * Compiles the pattern string and tries to find a substring matching it in the input data. The
397      * delimiter will be ignored. This is the same as invoking
398      * {@code findInLine(Pattern.compile(pattern))}.
399      *
400      * @param pattern
401      *            a string used to construct a pattern which is in turn used to
402      *            match a substring of the input data.
403      * @return the matched string or {@code null} if the pattern is not found
404      *         before the next line terminator.
405      * @throws IllegalStateException
406      *             if the {@code Scanner} is closed.
407      * @see #findInLine(Pattern)
408      */
findInLine(String pattern)409     public String findInLine(String pattern) {
410         return findInLine(Pattern.compile(pattern));
411     }
412 
413     /**
414      * Tries to find the pattern in the input between the current position and the specified
415      * horizon. Delimiters are ignored. If the pattern is found, the matched
416      * string will be returned, and the {@code Scanner} will advance to the end of the
417      * matched string. Otherwise, null will be returned and {@code Scanner} will not
418      * advance. When waiting for input, the {@code Scanner} may be blocked.
419      * <p>
420      * The {@code Scanner}'s search will never go more than {@code horizon} code points from current
421      * position. The position of {@code horizon} does have an effect on the result of the
422      * match. For example, when the input is "123" and current position is at zero,
423      * <code>findWithinHorizon(Pattern.compile("\\p{Digit}{3}"), 2)</code>
424      * will return {@code null}, while
425      * <code>findWithinHorizon(Pattern.compile("\\p{Digit}{3}"), 3)</code>
426      * will return {@code "123"}. {@code horizon} is treated as a transparent,
427      * non-anchoring bound. (refer to
428      * {@link Matcher#useTransparentBounds(boolean)} and
429      * {@link Matcher#useAnchoringBounds(boolean)})
430      * <p>
431      * A {@code horizon} whose value is zero will be ignored and the whole input will be
432      * used for search. In this situation, all the input may be cached.
433      *
434      * @param pattern
435      *            the pattern used to scan.
436      * @param horizon
437      *            the search limit.
438      * @return the matched string or {@code null} if the pattern is not found
439      *         within the specified {@code horizon}.
440      * @throws IllegalStateException
441      *             if the {@code Scanner} is closed.
442      * @throws IllegalArgumentException
443      *             if {@code horizon} is less than zero.
444      */
findWithinHorizon(Pattern pattern, int horizon)445     public String findWithinHorizon(Pattern pattern, int horizon) {
446         checkOpen();
447         checkNotNull(pattern);
448         if (horizon < 0) {
449             throw new IllegalArgumentException("horizon < 0");
450         }
451         matcher.usePattern(pattern);
452 
453         String result = null;
454         int horizonEndIndex = (horizon == 0) ? Integer.MAX_VALUE : findStartIndex + horizon;
455         while (true) {
456             // If horizon > 0, then search up to
457             // min( bufferLength, findStartIndex + horizon).
458             // Otherwise search until readable is exhausted.
459             int findEndIndex = Math.min(horizonEndIndex, bufferLength);
460             // If horizon == 0, consider horizon as always outside buffer.
461             boolean isHorizonInBuffer = (horizonEndIndex <= bufferLength);
462             // First, try to find pattern within buffer. If pattern can not be
463             // found in buffer, then expand the buffer and try again,
464             // util horizonEndIndex is exceeded or no more input left.
465             matcher.region(findStartIndex, findEndIndex);
466             if (matcher.find()) {
467                 if ((horizon == 0 && !matcher.hitEnd()) || isHorizonInBuffer || inputExhausted) {
468                     result = matcher.group();
469                     break;
470                 }
471             } else {
472                 // Pattern is not found in buffer while horizonEndIndex is
473                 // within buffer, or input is exhausted. Under this situation,
474                 // it can be judged that find fails.
475                 if (isHorizonInBuffer || inputExhausted) {
476                     break;
477                 }
478             }
479 
480             // Expand buffer and reset matcher if needed.
481             if (!inputExhausted) {
482                 readMore();
483                 resetMatcher();
484             }
485         }
486         if (result != null) {
487             findStartIndex = matcher.end();
488             matchSuccessful = true;
489         } else {
490             matchSuccessful = false;
491         }
492         return result;
493     }
494 
495     /**
496      * Tries to find the pattern in the input between the current position and the specified
497      * {@code horizon}. Delimiters are ignored. This call is the same as invoking
498      * {@code findWithinHorizon(Pattern.compile(pattern))}.
499      *
500      * @param pattern
501      *            the pattern used to scan.
502      * @param horizon
503      *            the search limit.
504      * @return the matched string, or {@code null} if the pattern is not found
505      *         within the specified horizon.
506      * @throws IllegalStateException
507      *             if the {@code Scanner} is closed.
508      * @throws IllegalArgumentException
509      *             if {@code horizon} is less than zero.
510      * @see #findWithinHorizon(Pattern, int)
511      */
findWithinHorizon(String pattern, int horizon)512     public String findWithinHorizon(String pattern, int horizon) {
513         return findWithinHorizon(Pattern.compile(pattern), horizon);
514     }
515 
516     /**
517      * Returns whether this {@code Scanner} has one or more tokens remaining to parse.
518      * This method will block if the data is still being read.
519      *
520      * @return {@code true} if this {@code Scanner} has one or more tokens remaining,
521      *         otherwise {@code false}.
522      * @throws IllegalStateException
523      *             if the {@code Scanner} has been closed.
524      */
hasNext()525     public boolean hasNext() {
526         return hasNext(ANY_PATTERN);
527     }
528 
529     /**
530      * Returns whether this {@code Scanner} has one or more tokens remaining to parse
531      * and the next token matches the given pattern. This method will block if the data is
532      * still being read.
533      *
534      * @param pattern
535      *            the pattern to check for.
536      * @return {@code true} if this {@code Scanner} has more tokens and the next token
537      *         matches the pattern, {@code false} otherwise.
538      * @throws IllegalStateException
539      *             if the {@code Scanner} has been closed.
540      */
hasNext(Pattern pattern)541     public boolean hasNext(Pattern pattern) {
542         checkOpen();
543         checkNotNull(pattern);
544         matchSuccessful = false;
545         prepareForScan();
546         // if the next token exists, set the match region, otherwise return
547         // false
548         if (!setTokenRegion()) {
549             recoverPreviousStatus();
550             return false;
551         }
552         matcher.usePattern(pattern);
553         boolean hasNext = false;
554         // check whether next token matches the specified pattern
555         if (matcher.matches()) {
556             cachedNextIndex = findStartIndex;
557             matchSuccessful = true;
558             hasNext = true;
559         }
560         recoverPreviousStatus();
561         return hasNext;
562     }
563 
564     /**
565      * Returns {@code true} if this {@code Scanner} has one or more tokens remaining to parse
566      * and the next token matches a pattern compiled from the given string. This method will
567      * block if the data is still being read. This call is equivalent to
568      * {@code hasNext(Pattern.compile(pattern))}.
569      *
570      * @param pattern
571      *            the string specifying the pattern to scan for
572      * @return {@code true} if the specified pattern matches this {@code Scanner}'s
573      *         next token, {@code false} otherwise.
574      * @throws IllegalStateException
575      *             if the {@code Scanner} has been closed.
576      */
hasNext(String pattern)577     public boolean hasNext(String pattern) {
578         return hasNext(Pattern.compile(pattern));
579     }
580 
581     /**
582      * Returns whether the next token can be translated into a valid
583      * {@code BigDecimal}.
584      *
585      * @return {@code true} if the next token can be translated into a valid
586      *         {@code BigDecimal}, otherwise {@code false.}
587      * @throws IllegalStateException
588      *             if the {@code Scanner} has been closed.
589      */
hasNextBigDecimal()590     public boolean hasNextBigDecimal() {
591         Pattern floatPattern = getFloatPattern();
592         boolean isBigDecimalValue = false;
593         if (hasNext(floatPattern)) {
594             String floatString = matcher.group();
595             floatString = removeLocaleInfoFromFloat(floatString);
596             try {
597                 cachedNextValue = new BigDecimal(floatString);
598                 isBigDecimalValue = true;
599             } catch (NumberFormatException e) {
600                 matchSuccessful = false;
601             }
602         }
603         return isBigDecimalValue;
604     }
605 
606     /**
607      * Returns whether the next token can be translated into a valid
608      * {@code BigInteger} in the default radix.
609      *
610      * @return {@code true} if the next token can be translated into a valid
611      *         {@code BigInteger}, otherwise {@code false}.
612      * @throws IllegalStateException
613      *             if the {@code Scanner} has been closed.
614      */
hasNextBigInteger()615     public boolean hasNextBigInteger() {
616         return hasNextBigInteger(currentRadix);
617     }
618 
619     /**
620      * Returns whether the next token can be translated into a valid
621      * {@code BigInteger} in the specified radix.
622      *
623      * @param radix
624      *            the radix used to translate the token into a
625      *            {@code BigInteger}.
626      * @return {@code true} if the next token can be translated into a valid
627      *         {@code BigInteger}, otherwise {@code false}.
628      * @throws IllegalStateException
629      *             if the {@code Scanner} has been closed.
630      */
hasNextBigInteger(int radix)631     public boolean hasNextBigInteger(int radix) {
632         Pattern integerPattern = getIntegerPattern(radix);
633         boolean isBigIntegerValue = false;
634         if (hasNext(integerPattern)) {
635             String intString = matcher.group();
636             intString = removeLocaleInfo(intString, int.class);
637             try {
638                 cachedNextValue = new BigInteger(intString, radix);
639                 isBigIntegerValue = true;
640             } catch (NumberFormatException e) {
641                 matchSuccessful = false;
642             }
643         }
644         return isBigIntegerValue;
645     }
646 
647     /**
648      * Returns whether the next token can be translated into a valid
649      * {@code boolean} value.
650      *
651      * @return {@code true} if the next token can be translated into a valid
652      *         {@code boolean} value, otherwise {@code false}.
653      * @throws IllegalStateException
654      *             if the {@code Scanner} has been closed.
655      */
hasNextBoolean()656     public boolean hasNextBoolean() {
657         return hasNext(BOOLEAN_PATTERN);
658     }
659 
660     /**
661      * Returns whether the next token can be translated into a valid
662      * {@code byte} value in the default radix.
663      *
664      * @return {@code true} if the next token can be translated into a valid
665      *         {@code byte} value, otherwise {@code false}.
666      * @throws IllegalStateException
667      *             if the {@code Scanner} has been closed.
668      */
hasNextByte()669     public boolean hasNextByte() {
670         return hasNextByte(currentRadix);
671     }
672 
673     /**
674      * Returns whether the next token can be translated into a valid
675      * {@code byte} value in the specified radix.
676      *
677      * @param radix
678      *            the radix used to translate the token into a {@code byte}
679      *            value
680      * @return {@code true} if the next token can be translated into a valid
681      *         {@code byte} value, otherwise {@code false}.
682      * @throws IllegalStateException
683      *             if the {@code Scanner} has been closed.
684      */
hasNextByte(int radix)685     public boolean hasNextByte(int radix) {
686         Pattern integerPattern = getIntegerPattern(radix);
687         boolean isByteValue = false;
688         if (hasNext(integerPattern)) {
689             String intString = matcher.group();
690             intString = removeLocaleInfo(intString, int.class);
691             try {
692                 cachedNextValue = Byte.valueOf(intString, radix);
693                 isByteValue = true;
694             } catch (NumberFormatException e) {
695                 matchSuccessful = false;
696             }
697         }
698         return isByteValue;
699     }
700 
701     /**
702      * Returns whether the next token translated into a valid {@code double}
703      * value.
704      *
705      * @return {@code true} if the next token can be translated into a valid
706      *         {@code double} value, otherwise {@code false}.
707      * @throws IllegalStateException
708      *             if the {@code Scanner} has been closed.
709      */
hasNextDouble()710     public boolean hasNextDouble() {
711         Pattern floatPattern = getFloatPattern();
712         boolean isDoubleValue = false;
713         if (hasNext(floatPattern)) {
714             String floatString = matcher.group();
715             floatString = removeLocaleInfoFromFloat(floatString);
716             try {
717                 cachedNextValue = Double.valueOf(floatString);
718                 isDoubleValue = true;
719             } catch (NumberFormatException e) {
720                 matchSuccessful = false;
721             }
722         }
723         return isDoubleValue;
724     }
725 
726     /**
727      * Returns whether the next token can be translated into a valid
728      * {@code float} value.
729      *
730      * @return {@code true} if the next token can be translated into a valid
731      *         {@code float} value, otherwise {@code false}.
732      * @throws IllegalStateException
733      *             if the {@code Scanner} has been closed.
734      */
hasNextFloat()735     public boolean hasNextFloat() {
736         Pattern floatPattern = getFloatPattern();
737         boolean isFloatValue = false;
738         if (hasNext(floatPattern)) {
739             String floatString = matcher.group();
740             floatString = removeLocaleInfoFromFloat(floatString);
741             try {
742                 cachedNextValue = Float.valueOf(floatString);
743                 isFloatValue = true;
744             } catch (NumberFormatException e) {
745                 matchSuccessful = false;
746             }
747         }
748         return isFloatValue;
749     }
750 
751     /**
752      * Returns whether the next token can be translated into a valid {@code int}
753      * value in the default radix.
754      *
755      * @return {@code true} if the next token can be translated into a valid
756      *         {@code int} value, otherwise {@code false}.
757      * @throws IllegalStateException
758      *             if the {@code Scanner} has been closed,
759      */
hasNextInt()760     public boolean hasNextInt() {
761         return hasNextInt(currentRadix);
762     }
763 
764     /**
765      * Returns whether the next token can be translated into a valid {@code int}
766      * value in the specified radix.
767      *
768      * @param radix
769      *            the radix used to translate the token into an {@code int}
770      *            value.
771      * @return {@code true} if the next token in this {@code Scanner}'s input can be
772      *         translated into a valid {@code int} value, otherwise
773      *         {@code false}.
774      * @throws IllegalStateException
775      *             if the {@code Scanner} has been closed.
776      */
hasNextInt(int radix)777     public boolean hasNextInt(int radix) {
778         Pattern integerPattern = getIntegerPattern(radix);
779         boolean isIntValue = false;
780         if (hasNext(integerPattern)) {
781             String intString = matcher.group();
782             intString = removeLocaleInfo(intString, int.class);
783             try {
784                 cachedNextValue = Integer.valueOf(intString, radix);
785                 isIntValue = true;
786             } catch (NumberFormatException e) {
787                 matchSuccessful = false;
788             }
789         }
790         return isIntValue;
791     }
792 
793     /**
794      * Returns true if there is a line terminator in the input.
795      * This method may block.
796      *
797      * @throws IllegalStateException if this {@code Scanner} is closed.
798      */
hasNextLine()799     public boolean hasNextLine() {
800         prepareForScan();
801         String result = findWithinHorizon(LINE_PATTERN, 0);
802         recoverPreviousStatus();
803         return result != null;
804     }
805 
806     /**
807      * Returns whether the next token can be translated into a valid
808      * {@code long} value in the default radix.
809      *
810      * @return {@code true} if the next token can be translated into a valid
811      *         {@code long} value, otherwise {@code false}.
812      * @throws IllegalStateException
813      *             if the {@code Scanner} has been closed.
814      */
hasNextLong()815     public boolean hasNextLong() {
816         return hasNextLong(currentRadix);
817     }
818 
819     /**
820      * Returns whether the next token can be translated into a valid
821      * {@code long} value in the specified radix.
822      *
823      * @param radix
824      *            the radix used to translate the token into a {@code long}
825      *            value.
826      * @return {@code true} if the next token can be translated into a valid
827      *         {@code long} value, otherwise {@code false}.
828      * @throws IllegalStateException
829      *             if the {@code Scanner} has been closed.
830      */
hasNextLong(int radix)831     public boolean hasNextLong(int radix) {
832         Pattern integerPattern = getIntegerPattern(radix);
833         boolean isLongValue = false;
834         if (hasNext(integerPattern)) {
835             String intString = matcher.group();
836             intString = removeLocaleInfo(intString, int.class);
837             try {
838                 cachedNextValue = Long.valueOf(intString, radix);
839                 isLongValue = true;
840             } catch (NumberFormatException e) {
841                 matchSuccessful = false;
842             }
843         }
844         return isLongValue;
845     }
846 
847     /**
848      * Returns whether the next token can be translated into a valid
849      * {@code short} value in the default radix.
850      *
851      * @return {@code true} if the next token can be translated into a valid
852      *         {@code short} value, otherwise {@code false}.
853      * @throws IllegalStateException
854      *             if the {@code Scanner} has been closed.
855      */
hasNextShort()856     public boolean hasNextShort() {
857         return hasNextShort(currentRadix);
858     }
859 
860     /**
861      * Returns whether the next token can be translated into a valid
862      * {@code short} value in the specified radix.
863      *
864      * @param radix
865      *            the radix used to translate the token into a {@code short}
866      *            value.
867      * @return {@code true} if the next token can be translated into a valid
868      *         {@code short} value, otherwise {@code false}.
869      * @throws IllegalStateException
870      *             if the {@code Scanner} has been closed.
871      */
hasNextShort(int radix)872     public boolean hasNextShort(int radix) {
873         Pattern integerPattern = getIntegerPattern(radix);
874         boolean isShortValue = false;
875         if (hasNext(integerPattern)) {
876             String intString = matcher.group();
877             intString = removeLocaleInfo(intString, int.class);
878             try {
879                 cachedNextValue = Short.valueOf(intString, radix);
880                 isShortValue = true;
881             } catch (NumberFormatException e) {
882                 matchSuccessful = false;
883             }
884         }
885         return isShortValue;
886     }
887 
888     /**
889      * Returns the last {@code IOException} that was raised while reading from the underlying
890      * input, or {@code null} if none was thrown.
891      */
ioException()892     public IOException ioException() {
893         return lastIOException;
894     }
895 
896     /**
897      * Returns the {@code Locale} of this {@code Scanner}.
898      */
locale()899     public Locale locale() {
900         return locale;
901     }
902 
setLocale(Locale locale)903     private void setLocale(Locale locale) {
904         this.locale = locale;
905         this.decimalFormat = null;
906         this.cachedFloatPattern = null;
907         this.cachedIntegerPatternRadix = -1;
908         this.cachedIntegerPattern = null;
909     }
910 
911     /**
912      * Returns the result of the last matching operation.
913      * <p>
914      * The next* and find* methods return the match result in the case of a
915      * successful match.
916      *
917      * @return the match result of the last successful match operation
918      * @throws IllegalStateException
919      *             if the match result is not available, of if the last match
920      *             was not successful.
921      */
match()922     public MatchResult match() {
923         if (!matchSuccessful) {
924             throw new IllegalStateException();
925         }
926         return matcher.toMatchResult();
927     }
928 
929     /**
930      * Returns the next token. The token will be both prefixed and suffixed by
931      * the delimiter that is currently being used (or a string that matches the
932      * delimiter pattern). This method will block if input is being read.
933      *
934      * @return the next complete token.
935      * @throws IllegalStateException
936      *             if this {@code Scanner} has been closed.
937      * @throws NoSuchElementException
938      *             if input has been exhausted.
939      */
next()940     public String next() {
941         return next(ANY_PATTERN);
942     }
943 
944     /**
945      * Returns the next token if it matches the specified pattern. The token
946      * will be both prefixed and suffixed by the delimiter that is currently
947      * being used (or a string that matches the delimiter pattern). This method will block
948      * if input is being read.
949      *
950      * @param pattern
951      *            the specified pattern to scan.
952      * @return the next token.
953      * @throws IllegalStateException
954      *             if this {@code Scanner} has been closed.
955      * @throws NoSuchElementException
956      *             if input has been exhausted.
957      * @throws InputMismatchException
958      *             if the next token does not match the pattern given.
959      */
next(Pattern pattern)960     public String next(Pattern pattern) {
961         checkOpen();
962         checkNotNull(pattern);
963         matchSuccessful = false;
964         prepareForScan();
965         if (!setTokenRegion()) {
966             recoverPreviousStatus();
967             // if setting match region fails
968             throw new NoSuchElementException();
969         }
970         matcher.usePattern(pattern);
971         if (!matcher.matches()) {
972             recoverPreviousStatus();
973             throw new InputMismatchException();
974 
975         }
976         matchSuccessful = true;
977         return matcher.group();
978     }
979 
980     /**
981      * Returns the next token if it matches the specified pattern. The token
982      * will be both prefixed and suffixed by the delimiter that is currently
983      * being used (or a string that matches the delimiter pattern). This method will block
984      * if input is being read. Calling this method is equivalent to
985      * {@code next(Pattern.compile(pattern))}.
986      *
987      * @param pattern
988      *            the string specifying the pattern to scan for.
989      * @return the next token.
990      * @throws IllegalStateException
991      *             if this {@code Scanner} has been closed.
992      * @throws NoSuchElementException
993      *             if input has been exhausted.
994      * @throws InputMismatchException
995      *             if the next token does not match the pattern given.
996      */
next(String pattern)997     public String next(String pattern) {
998         return next(Pattern.compile(pattern));
999     }
1000 
1001     /**
1002      * Returns the next token as a {@code BigDecimal}. This method will block if input is
1003      * being read. If the next token can be translated into a {@code BigDecimal}
1004      * the following is done: All {@code Locale}-specific prefixes, group separators,
1005      * and {@code Locale}-specific suffixes are removed. Then non-ASCII digits are
1006      * mapped into ASCII digits via {@link Character#digit(char, int)}, and a
1007      * negative sign (-) is added if the {@code Locale}-specific negative prefix or
1008      * suffix was present. Finally the resulting string is passed to
1009      * {@code BigDecimal(String) }.
1010      *
1011      * @return the next token as a {@code BigDecimal}.
1012      * @throws IllegalStateException
1013      *             if this {@code Scanner} has been closed.
1014      * @throws NoSuchElementException
1015      *             if input has been exhausted.
1016      * @throws InputMismatchException
1017      *             if the next token can not be translated into a valid
1018      *             {@code BigDecimal}.
1019      */
nextBigDecimal()1020     public BigDecimal nextBigDecimal() {
1021         checkOpen();
1022         Object obj = cachedNextValue;
1023         cachedNextValue = null;
1024         if (obj instanceof BigDecimal) {
1025             findStartIndex = cachedNextIndex;
1026             return (BigDecimal) obj;
1027         }
1028         Pattern floatPattern = getFloatPattern();
1029         String floatString = next(floatPattern);
1030         floatString = removeLocaleInfoFromFloat(floatString);
1031         BigDecimal bigDecimalValue;
1032         try {
1033             bigDecimalValue = new BigDecimal(floatString);
1034         } catch (NumberFormatException e) {
1035             matchSuccessful = false;
1036             recoverPreviousStatus();
1037             throw new InputMismatchException();
1038         }
1039         return bigDecimalValue;
1040     }
1041 
1042     /**
1043      * Returns the next token as a {@code BigInteger} in the current radix.
1044      * This method may block for more input.
1045      *
1046      * @throws IllegalStateException
1047      *             if this {@code Scanner} has been closed.
1048      * @throws NoSuchElementException
1049      *             if input has been exhausted.
1050      * @throws InputMismatchException
1051      *             if the next token can not be translated into a valid
1052      *             {@code BigInteger}.
1053      */
nextBigInteger()1054     public BigInteger nextBigInteger() {
1055         return nextBigInteger(currentRadix);
1056     }
1057 
1058     /**
1059      * Returns the next token as a {@code BigInteger} with the specified radix.
1060      * This method will block if input is being read. If the next token can be translated
1061      * into a {@code BigInteger} the following is done: All {@code Locale}-specific
1062      * prefixes, group separators, and {@code Locale}-specific suffixes are removed.
1063      * Then non-ASCII digits are mapped into ASCII digits via
1064      * {@link Character#digit(char, int)}, and a negative sign (-) is added if the
1065      * {@code Locale}-specific negative prefix or suffix was present. Finally the
1066      * resulting String is passed to {@link BigInteger#BigInteger(String, int)}}
1067      * with the specified radix.
1068      *
1069      * @param radix
1070      *            the radix used to translate the token into a
1071      *            {@code BigInteger}.
1072      * @return the next token as a {@code BigInteger}
1073      * @throws IllegalStateException
1074      *             if this {@code Scanner} has been closed.
1075      * @throws NoSuchElementException
1076      *             if input has been exhausted.
1077      * @throws InputMismatchException
1078      *             if the next token can not be translated into a valid
1079      *             {@code BigInteger}.
1080      */
nextBigInteger(int radix)1081     public BigInteger nextBigInteger(int radix) {
1082         checkOpen();
1083         Object obj = cachedNextValue;
1084         cachedNextValue = null;
1085         if (obj instanceof BigInteger) {
1086             findStartIndex = cachedNextIndex;
1087             return (BigInteger) obj;
1088         }
1089         Pattern integerPattern = getIntegerPattern(radix);
1090         String intString = next(integerPattern);
1091         intString = removeLocaleInfo(intString, int.class);
1092         BigInteger bigIntegerValue;
1093         try {
1094             bigIntegerValue = new BigInteger(intString, radix);
1095         } catch (NumberFormatException e) {
1096             matchSuccessful = false;
1097             recoverPreviousStatus();
1098             throw new InputMismatchException();
1099         }
1100         return bigIntegerValue;
1101     }
1102 
1103     /**
1104      * Returns the next token as a {@code boolean}. This method will block if input is
1105      * being read.
1106      *
1107      * @return the next token as a {@code boolean}.
1108      * @throws IllegalStateException
1109      *             if this {@code Scanner} has been closed.
1110      * @throws NoSuchElementException
1111      *             if input has been exhausted.
1112      * @throws InputMismatchException
1113      *             if the next token can not be translated into a valid
1114      *             {@code boolean} value.
1115      */
nextBoolean()1116     public boolean nextBoolean() {
1117         return Boolean.parseBoolean(next(BOOLEAN_PATTERN));
1118     }
1119 
1120     /**
1121      * Returns the next token as a {@code byte} in the current radix.
1122      * This method may block for more input.
1123      *
1124      * @throws IllegalStateException
1125      *             if this {@code Scanner} has been closed.
1126      * @throws NoSuchElementException
1127      *             if input has been exhausted.
1128      * @throws InputMismatchException
1129      *             if the next token can not be translated into a valid
1130      *             {@code byte} value.
1131      */
nextByte()1132     public byte nextByte() {
1133         return nextByte(currentRadix);
1134     }
1135 
1136     /**
1137      * Returns the next token as a {@code byte} with the specified radix. Will
1138      * block if input is being read. If the next token can be translated into a
1139      * {@code byte} the following is done: All {@code Locale}-specific prefixes, group
1140      * separators, and {@code Locale}-specific suffixes are removed. Then non-ASCII
1141      * digits are mapped into ASCII digits via
1142      * {@link Character#digit(char, int)}, and a negative sign (-) is added if the
1143      * {@code Locale}-specific negative prefix or suffix was present. Finally the
1144      * resulting String is passed to {@link Byte#parseByte(String, int)}} with
1145      * the specified radix.
1146      *
1147      * @param radix
1148      *            the radix used to translate the token into {@code byte} value.
1149      * @return the next token as a {@code byte}.
1150      * @throws IllegalStateException
1151      *             if this {@code Scanner} has been closed.
1152      * @throws NoSuchElementException
1153      *             if input has been exhausted.
1154      * @throws InputMismatchException
1155      *             if the next token can not be translated into a valid
1156      *             {@code byte} value.
1157      */
1158     @SuppressWarnings("boxing")
nextByte(int radix)1159     public byte nextByte(int radix) {
1160         checkOpen();
1161         Object obj = cachedNextValue;
1162         cachedNextValue = null;
1163         if (obj instanceof Byte) {
1164             findStartIndex = cachedNextIndex;
1165             return (Byte) obj;
1166         }
1167         Pattern integerPattern = getIntegerPattern(radix);
1168         String intString = next(integerPattern);
1169         intString = removeLocaleInfo(intString, int.class);
1170         byte byteValue = 0;
1171         try {
1172             byteValue = Byte.parseByte(intString, radix);
1173         } catch (NumberFormatException e) {
1174             matchSuccessful = false;
1175             recoverPreviousStatus();
1176             throw new InputMismatchException();
1177         }
1178         return byteValue;
1179     }
1180 
1181     /**
1182      * Returns the next token as a {@code double}. This method will block if input is being
1183      * read. If the next token can be translated into a {@code double} the
1184      * following is done: All {@code Locale}-specific prefixes, group separators, and
1185      * {@code Locale}-specific suffixes are removed. Then non-ASCII digits are mapped
1186      * into ASCII digits via {@link Character#digit(char, int)}, and a negative
1187      * sign (-) is added if the {@code Locale}-specific negative prefix or suffix was
1188      * present. Finally the resulting String is passed to
1189      * {@link Double#parseDouble(String)}}. If the token matches the localized
1190      * NaN or infinity strings, it is also passed to
1191      * {@link Double#parseDouble(String)}}.
1192      *
1193      * @return the next token as a {@code double}.
1194      * @throws IllegalStateException
1195      *             if this {@code Scanner} has been closed.
1196      * @throws NoSuchElementException
1197      *             if input has been exhausted.
1198      * @throws InputMismatchException
1199      *             if the next token can not be translated into a valid
1200      *             {@code double} value.
1201      */
1202     @SuppressWarnings("boxing")
nextDouble()1203     public double nextDouble() {
1204         checkOpen();
1205         Object obj = cachedNextValue;
1206         cachedNextValue = null;
1207         if (obj instanceof Double) {
1208             findStartIndex = cachedNextIndex;
1209             return (Double) obj;
1210         }
1211         Pattern floatPattern = getFloatPattern();
1212         String floatString = next(floatPattern);
1213         floatString = removeLocaleInfoFromFloat(floatString);
1214         double doubleValue;
1215         try {
1216             doubleValue = Double.parseDouble(floatString);
1217         } catch (NumberFormatException e) {
1218             matchSuccessful = false;
1219             recoverPreviousStatus();
1220             throw new InputMismatchException();
1221         }
1222         return doubleValue;
1223     }
1224 
1225     /**
1226      * Returns the next token as a {@code float}. This method will block if input is being
1227      * read. If the next token can be translated into a {@code float} the
1228      * following is done: All {@code Locale}-specific prefixes, group separators, and
1229      * {@code Locale}-specific suffixes are removed. Then non-ASCII digits are mapped
1230      * into ASCII digits via {@link Character#digit(char, int)}, and a negative
1231      * sign (-) is added if the {@code Locale}-specific negative prefix or suffix was
1232      * present. Finally the resulting String is passed to
1233      * {@link Float#parseFloat(String)}}.If the token matches the localized NaN
1234      * or infinity strings, it is also passed to
1235      * {@link Float#parseFloat(String)}}.
1236      *
1237      * @return the next token as a {@code float}.
1238      * @throws IllegalStateException
1239      *             if this {@code Scanner} has been closed.
1240      * @throws NoSuchElementException
1241      *             if input has been exhausted.
1242      * @throws InputMismatchException
1243      *             if the next token can not be translated into a valid
1244      *             {@code float} value.
1245      */
1246     @SuppressWarnings("boxing")
nextFloat()1247     public float nextFloat() {
1248         checkOpen();
1249         Object obj = cachedNextValue;
1250         cachedNextValue = null;
1251         if (obj instanceof Float) {
1252             findStartIndex = cachedNextIndex;
1253             return (Float) obj;
1254         }
1255         Pattern floatPattern = getFloatPattern();
1256         String floatString = next(floatPattern);
1257         floatString = removeLocaleInfoFromFloat(floatString);
1258         float floatValue;
1259         try {
1260             floatValue = Float.parseFloat(floatString);
1261         } catch (NumberFormatException e) {
1262             matchSuccessful = false;
1263             recoverPreviousStatus();
1264             throw new InputMismatchException();
1265         }
1266         return floatValue;
1267     }
1268 
1269     /**
1270      * Returns the next token as an {@code int} in the current radix.
1271      * This method may block for more input.
1272      *
1273      * @throws IllegalStateException
1274      *             if this {@code Scanner} has been closed.
1275      * @throws NoSuchElementException
1276      *             if input has been exhausted.
1277      * @throws InputMismatchException
1278      *             if the next token can not be translated into a valid
1279      *             {@code int} value.
1280      */
nextInt()1281     public int nextInt() {
1282         return nextInt(currentRadix);
1283     }
1284 
1285     /**
1286      * Returns the next token as an {@code int} with the specified radix. This method will
1287      * block if input is being read. If the next token can be translated into an
1288      * {@code int} the following is done: All {@code Locale}-specific prefixes, group
1289      * separators, and {@code Locale}-specific suffixes are removed. Then non-ASCII
1290      * digits are mapped into ASCII digits via
1291      * {@link Character#digit(char, int)}, and a negative sign (-) is added if the
1292      * {@code Locale}-specific negative prefix or suffix was present. Finally the
1293      * resulting String is passed to {@link Integer#parseInt(String, int)} with
1294      * the specified radix.
1295      *
1296      * @param radix
1297      *            the radix used to translate the token into an {@code int}
1298      *            value.
1299      * @return the next token as an {@code int}.
1300      * @throws IllegalStateException
1301      *             if this {@code Scanner} has been closed.
1302      * @throws NoSuchElementException
1303      *             if input has been exhausted.
1304      * @throws InputMismatchException
1305      *             if the next token can not be translated into a valid
1306      *             {@code int} value.
1307      */
1308     @SuppressWarnings("boxing")
nextInt(int radix)1309     public int nextInt(int radix) {
1310         checkOpen();
1311         Object obj = cachedNextValue;
1312         cachedNextValue = null;
1313         if (obj instanceof Integer) {
1314             findStartIndex = cachedNextIndex;
1315             return (Integer) obj;
1316         }
1317         Pattern integerPattern = getIntegerPattern(radix);
1318         String intString = next(integerPattern);
1319         intString = removeLocaleInfo(intString, int.class);
1320         int intValue;
1321         try {
1322             intValue = Integer.parseInt(intString, radix);
1323         } catch (NumberFormatException e) {
1324             matchSuccessful = false;
1325             recoverPreviousStatus();
1326             throw new InputMismatchException();
1327         }
1328         return intValue;
1329     }
1330 
1331     /**
1332      * Returns the skipped input and advances the {@code Scanner} to the beginning of
1333      * the next line. The returned result will exclude any line terminator. When
1334      * searching, if no line terminator is found, then a large amount of input
1335      * will be cached. If no line at all can be found, a {@code NoSuchElementException}
1336      * will be thrown.
1337      *
1338      * @return the skipped line.
1339      * @throws IllegalStateException
1340      *             if the {@code Scanner} is closed.
1341      * @throws NoSuchElementException
1342      *             if no line can be found, e.g. when input is an empty string.
1343      */
nextLine()1344     public String nextLine() {
1345         checkOpen();
1346 
1347         matcher.usePattern(LINE_PATTERN);
1348         matcher.region(findStartIndex, bufferLength);
1349 
1350         String result;
1351         while (true) {
1352             if (matcher.find()) {
1353                 if (inputExhausted || matcher.end() != bufferLength
1354                         || bufferLength < buffer.capacity()) {
1355                     matchSuccessful = true;
1356                     findStartIndex = matcher.end();
1357                     result = matcher.group();
1358                     break;
1359                 }
1360             } else {
1361                 if (inputExhausted) {
1362                     matchSuccessful = false;
1363                     throw new NoSuchElementException();
1364                 }
1365             }
1366             if (!inputExhausted) {
1367                 readMore();
1368                 resetMatcher();
1369             }
1370         }
1371         // Find text without line terminator here.
1372         if (result != null) {
1373             Matcher terminatorMatcher = LINE_TERMINATOR.matcher(result);
1374             if (terminatorMatcher.find()) {
1375                 result = result.substring(0, terminatorMatcher.start());
1376             }
1377         }
1378         return result;
1379     }
1380 
1381     /**
1382      * Returns the next token as a {@code long} in the current radix.
1383      * This method may block for more input.
1384      *
1385      * @throws IllegalStateException
1386      *             if this {@code Scanner} has been closed.
1387      * @throws NoSuchElementException
1388      *             if input has been exhausted.
1389      * @throws InputMismatchException
1390      *             if the next token can not be translated into a valid
1391      *             {@code long} value.
1392      */
nextLong()1393     public long nextLong() {
1394         return nextLong(currentRadix);
1395     }
1396 
1397     /**
1398      * Returns the next token as a {@code long} with the specified radix. This method will
1399      * block if input is being read. If the next token can be translated into a
1400      * {@code long} the following is done: All {@code Locale}-specific prefixes, group
1401      * separators, and {@code Locale}-specific suffixes are removed. Then non-ASCII
1402      * digits are mapped into ASCII digits via
1403      * {@link Character#digit(char, int)}, and a negative sign (-) is added if the
1404      * {@code Locale}-specific negative prefix or suffix was present. Finally the
1405      * resulting String is passed to {@link Long#parseLong(String, int)}} with
1406      * the specified radix.
1407      *
1408      * @param radix
1409      *            the radix used to translate the token into a {@code long}
1410      *            value.
1411      * @return the next token as a {@code long}.
1412      * @throws IllegalStateException
1413      *             if this {@code Scanner} has been closed.
1414      * @throws NoSuchElementException
1415      *             if input has been exhausted.
1416      * @throws InputMismatchException
1417      *             if the next token can not be translated into a valid
1418      *             {@code long} value.
1419      */
1420     @SuppressWarnings("boxing")
nextLong(int radix)1421     public long nextLong(int radix) {
1422         checkOpen();
1423         Object obj = cachedNextValue;
1424         cachedNextValue = null;
1425         if (obj instanceof Long) {
1426             findStartIndex = cachedNextIndex;
1427             return (Long) obj;
1428         }
1429         Pattern integerPattern = getIntegerPattern(radix);
1430         String intString = next(integerPattern);
1431         intString = removeLocaleInfo(intString, int.class);
1432         long longValue;
1433         try {
1434             longValue = Long.parseLong(intString, radix);
1435         } catch (NumberFormatException e) {
1436             matchSuccessful = false;
1437             recoverPreviousStatus();
1438             throw new InputMismatchException();
1439         }
1440         return longValue;
1441     }
1442 
1443     /**
1444      * Returns the next token as a {@code short} in the current radix.
1445      * This method may block for more input.
1446      *
1447      * @throws IllegalStateException
1448      *             if this {@code Scanner} has been closed.
1449      * @throws NoSuchElementException
1450      *             if input has been exhausted.
1451      * @throws InputMismatchException
1452      *             if the next token can not be translated into a valid
1453      *             {@code short} value.
1454      */
nextShort()1455     public short nextShort() {
1456         return nextShort(currentRadix);
1457     }
1458 
1459     /**
1460      * Returns the next token as a {@code short} with the specified radix. This method will
1461      * block if input is being read. If the next token can be translated into a
1462      * {@code short} the following is done: All {@code Locale}-specific prefixes, group
1463      * separators, and {@code Locale}-specific suffixes are removed. Then non-ASCII
1464      * digits are mapped into ASCII digits via
1465      * {@link Character#digit(char, int)}, and a negative sign (-) is added if the
1466      * {@code Locale}-specific negative prefix or suffix was present. Finally the
1467      * resulting String is passed to {@link Short#parseShort(String, int)}}
1468      * with the specified radix.
1469      *
1470      * @param radix
1471      *            the radix used to translate the token into {@code short}
1472      *            value.
1473      * @return the next token as a {@code short}.
1474      * @throws IllegalStateException
1475      *             if this {@code Scanner} has been closed.
1476      * @throws NoSuchElementException
1477      *             if input has been exhausted.
1478      * @throws InputMismatchException
1479      *             if the next token can not be translated into a valid
1480      *             {@code short} value.
1481      */
1482     @SuppressWarnings("boxing")
nextShort(int radix)1483     public short nextShort(int radix) {
1484         checkOpen();
1485         Object obj = cachedNextValue;
1486         cachedNextValue = null;
1487         if (obj instanceof Short) {
1488             findStartIndex = cachedNextIndex;
1489             return (Short) obj;
1490         }
1491         Pattern integerPattern = getIntegerPattern(radix);
1492         String intString = next(integerPattern);
1493         intString = removeLocaleInfo(intString, int.class);
1494         short shortValue;
1495         try {
1496             shortValue = Short.parseShort(intString, radix);
1497         } catch (NumberFormatException e) {
1498             matchSuccessful = false;
1499             recoverPreviousStatus();
1500             throw new InputMismatchException();
1501         }
1502         return shortValue;
1503     }
1504 
1505     /**
1506      * Return the radix of this {@code Scanner}.
1507      *
1508      * @return the radix of this {@code Scanner}
1509      */
radix()1510     public int radix() {
1511         return currentRadix;
1512     }
1513 
1514     /**
1515      * Tries to use specified pattern to match input starting from the current position.
1516      * The delimiter will be ignored. If a match is found, the matched input will be
1517      * skipped. If an anchored match of the specified pattern succeeds, the corresponding input
1518      * will also be skipped. Otherwise, a {@code NoSuchElementException} will be thrown.
1519      * Patterns that can match a lot of input may cause the {@code Scanner} to read
1520      * in a large amount of input.
1521      *
1522      * @param pattern
1523      *            used to skip over input.
1524      * @return the {@code Scanner} itself.
1525      * @throws IllegalStateException
1526      *             if the {@code Scanner} is closed.
1527      * @throws NoSuchElementException
1528      *             if the specified pattern match fails.
1529      */
skip(Pattern pattern)1530     public Scanner skip(Pattern pattern) {
1531         checkOpen();
1532         checkNotNull(pattern);
1533         matcher.usePattern(pattern);
1534         matcher.region(findStartIndex, bufferLength);
1535         while (true) {
1536             if (matcher.lookingAt()) {
1537                 boolean matchInBuffer = matcher.end() < bufferLength
1538                         || (matcher.end() == bufferLength && inputExhausted);
1539                 if (matchInBuffer) {
1540                     matchSuccessful = true;
1541                     findStartIndex = matcher.end();
1542                     break;
1543                 }
1544             } else {
1545                 if (inputExhausted) {
1546                     matchSuccessful = false;
1547                     throw new NoSuchElementException();
1548                 }
1549             }
1550             if (!inputExhausted) {
1551                 readMore();
1552                 resetMatcher();
1553             }
1554         }
1555         return this;
1556     }
1557 
1558     /**
1559      * Tries to use the specified string to construct a pattern and then uses
1560      * the constructed pattern to match input starting from the current position. The
1561      * delimiter will be ignored. This call is the same as invoke
1562      * {@code skip(Pattern.compile(pattern))}.
1563      *
1564      * @param pattern
1565      *            the string used to construct a pattern which in turn is used to
1566      *            match input.
1567      * @return the {@code Scanner} itself.
1568      * @throws IllegalStateException
1569      *             if the {@code Scanner} is closed.
1570      */
1571     public Scanner skip(String pattern) {
1572         return skip(Pattern.compile(pattern));
1573     }
1574 
1575     /**
1576      * Returns a string representation of this {@code Scanner}. The information
1577      * returned may be helpful for debugging. The format of the string is unspecified.
1578      *
1579      * @return a string representation of this {@code Scanner}.
1580      */
1581     @Override
1582     public String toString() {
1583         return getClass().getName() +
1584                 "[delimiter=" + delimiter +
1585                 ",findStartIndex=" + findStartIndex +
1586                 ",matchSuccessful=" + matchSuccessful +
1587                 ",closed=" + closed +
1588                 "]";
1589     }
1590 
1591     /**
1592      * Sets the delimiting pattern of this {@code Scanner}.
1593      *
1594      * @param pattern
1595      *            the delimiting pattern to use.
1596      * @return this {@code Scanner}.
1597      */
1598     public Scanner useDelimiter(Pattern pattern) {
1599         delimiter = pattern;
1600         return this;
1601     }
1602 
1603     /**
1604      * Sets the delimiting pattern of this {@code Scanner} with a pattern compiled from
1605      * the supplied string value.
1606      *
1607      * @param pattern
1608      *            a string from which a {@code Pattern} can be compiled.
1609      * @return this {@code Scanner}.
1610      */
1611     public Scanner useDelimiter(String pattern) {
1612         return useDelimiter(Pattern.compile(pattern));
1613     }
1614 
1615     /**
1616      * Sets the {@code Locale} of this {@code Scanner} to a specified {@code Locale}.
1617      *
1618      * @param l
1619      *            the specified {@code Locale} to use.
1620      * @return this {@code Scanner}.
1621      */
1622     public Scanner useLocale(Locale l) {
1623         if (l == null) {
1624             throw new NullPointerException("l == null");
1625         }
1626         setLocale(l);
1627         return this;
1628     }
1629 
1630     /**
1631      * Sets the radix of this {@code Scanner} to the specified radix.
1632      *
1633      * @param radix
1634      *            the specified radix to use.
1635      * @return this {@code Scanner}.
1636      */
1637     public Scanner useRadix(int radix) {
1638         checkRadix(radix);
1639         this.currentRadix = radix;
1640         return this;
1641     }
1642 
1643     private void checkRadix(int radix) {
1644         if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) {
1645             throw new IllegalArgumentException("Invalid radix: " + radix);
1646         }
1647     }
1648 
1649     /**
1650      * Remove is not a supported operation on {@code Scanner}.
1651      *
1652      * @throws UnsupportedOperationException
1653      *             if this method is invoked.
1654      */
1655     public void remove() {
1656         throw new UnsupportedOperationException();
1657     }
1658 
1659     private void checkOpen() {
1660         if (closed) {
1661             throw new IllegalStateException();
1662         }
1663     }
1664 
1665     private void checkNotNull(Pattern pattern) {
1666         if (pattern == null) {
1667             throw new NullPointerException("pattern == null");
1668         }
1669     }
1670 
1671     /*
1672      * Change the matcher's input after modifying the contents of the buffer.
1673      * The current implementation of Matcher causes a copy of the buffer to be taken.
1674      */
1675     private void resetMatcher() {
1676         matcher.reset(buffer);
1677         matcher.region(findStartIndex, bufferLength);
1678     }
1679 
1680     /*
1681      * Recover buffer space for characters that are already processed and save the matcher's state
1682      * in case parsing fails. See recoverPrevousState. This method must be called before
1683      * any buffer offsets are calculated.
1684      */
1685     private void prepareForScan() {
1686         // Compacting the buffer recovers space taken by already processed characters. This does not
1687         // prevent the buffer growing in all situations but keeps the buffer small when delimiters
1688         // exist regularly.
1689         if (findStartIndex >= buffer.capacity() / 2) {
1690             // When over half the buffer is filled with characters no longer being considered by the
1691             // scanner we take the cost of compacting the buffer.
1692 
1693             // Move all characters from [findStartIndex, findStartIndex + remaining()) to
1694             // [0, remaining()).
1695             int oldPosition = buffer.position();
1696             buffer.position(findStartIndex);
1697             buffer.compact();
1698             buffer.position(oldPosition);
1699 
1700             // Update Scanner state to reflect the new buffer state.
1701             bufferLength -= findStartIndex;
1702             findStartIndex = 0;
1703             preStartIndex = -1;
1704 
1705             // The matcher must also be informed that the buffer has changed because it operates on
1706             // a String copy.
1707             resetMatcher();
1708         }
1709 
1710         // Save the matcher's last find position so it can be returned to if the next token cannot
1711         // be parsed.
1712         preStartIndex = findStartIndex;
1713     }
1714 
1715     /*
1716      * Change the matcher's status to last find position
1717      */
recoverPreviousStatus()1718     private void recoverPreviousStatus() {
1719         findStartIndex = preStartIndex;
1720     }
1721 
getIntegerPattern(int radix)1722     private Pattern getIntegerPattern(int radix) {
1723         checkRadix(radix);
1724 
1725         if (decimalFormat == null) {
1726             decimalFormat = (DecimalFormat) NumberFormat.getInstance(locale);
1727         }
1728 
1729         if (cachedIntegerPatternRadix == radix) {
1730             return cachedIntegerPattern;
1731         }
1732 
1733         String digits = "0123456789abcdefghijklmnopqrstuvwxyz";
1734         String ASCIIDigit = digits.substring(0, radix);
1735         String nonZeroASCIIDigit = digits.substring(1, radix);
1736 
1737         String digit = "((?i)[" + ASCIIDigit + "]|\\p{javaDigit})";
1738         String nonZeroDigit = "((?i)[" + nonZeroASCIIDigit + "]|([\\p{javaDigit}&&[^0]]))";
1739         String numeral = getNumeral(digit, nonZeroDigit);
1740 
1741         String regex = "(([-+]?(" + numeral + ")))|" +
1742             "(" + addPositiveSign(numeral) + ")|" +
1743             "(" + addNegativeSign(numeral) + ")";
1744 
1745         cachedIntegerPatternRadix = radix;
1746         cachedIntegerPattern = Pattern.compile(regex);
1747         return cachedIntegerPattern;
1748     }
1749 
getFloatPattern()1750     private Pattern getFloatPattern() {
1751         if (decimalFormat == null) {
1752             decimalFormat = (DecimalFormat) NumberFormat.getInstance(locale);
1753         }
1754 
1755         if (cachedFloatPattern != null) {
1756             return cachedFloatPattern;
1757         }
1758 
1759         DecimalFormatSymbols dfs = decimalFormat.getDecimalFormatSymbols();
1760 
1761         String digit = "([0-9]|(\\p{javaDigit}))";
1762         String nonZeroDigit = "[\\p{javaDigit}&&[^0]]";
1763         String numeral = getNumeral(digit, nonZeroDigit);
1764 
1765         String decimalSeparator = "\\" + dfs.getDecimalSeparator();
1766         String decimalNumeral = "(" + numeral + "|" +
1767             numeral + decimalSeparator + digit + "*+|" +
1768             decimalSeparator + digit + "++)";
1769         String exponent = "([eE][+-]?" + digit + "+)?";
1770 
1771         String decimal = "(([-+]?" + decimalNumeral + "(" + exponent + "?)" + ")|" +
1772             "(" + addPositiveSign(decimalNumeral) + "(" + exponent + "?)" + ")|" +
1773             "(" + addNegativeSign(decimalNumeral) + "(" + exponent + "?)" + "))";
1774 
1775         String hexFloat = "([-+]?0[xX][0-9a-fA-F]*\\.[0-9a-fA-F]+([pP][-+]?[0-9]+)?)";
1776         String localNaN = dfs.getNaN();
1777         String localeInfinity = dfs.getInfinity();
1778         String nonNumber = "(NaN|\\Q" + localNaN + "\\E|Infinity|\\Q" + localeInfinity + "\\E)";
1779         String signedNonNumber = "((([-+]?(" + nonNumber + ")))|" +
1780             "(" + addPositiveSign(nonNumber) + ")|" +
1781             "(" + addNegativeSign(nonNumber) + "))";
1782 
1783         cachedFloatPattern = Pattern.compile(decimal + "|" + hexFloat + "|" + signedNonNumber);
1784         return cachedFloatPattern;
1785     }
1786 
getNumeral(String digit, String nonZeroDigit)1787     private String getNumeral(String digit, String nonZeroDigit) {
1788         String groupSeparator = "\\" + decimalFormat.getDecimalFormatSymbols().getGroupingSeparator();
1789         String groupedNumeral = "(" + nonZeroDigit + digit + "?" + digit + "?" +
1790             "(" + groupSeparator + digit + digit + digit + ")+)";
1791         return "((" + digit + "++)|" + groupedNumeral + ")";
1792     }
1793 
1794     /*
1795      * Add the locale specific positive prefixes and suffixes to the pattern
1796      */
addPositiveSign(String unsignedNumeral)1797     private String addPositiveSign(String unsignedNumeral) {
1798         String positivePrefix = "";
1799         String positiveSuffix = "";
1800         if (!decimalFormat.getPositivePrefix().isEmpty()) {
1801             positivePrefix = "\\Q" + decimalFormat.getPositivePrefix() + "\\E";
1802         }
1803         if (!decimalFormat.getPositiveSuffix().isEmpty()) {
1804             positiveSuffix = "\\Q" + decimalFormat.getPositiveSuffix() + "\\E";
1805         }
1806         return positivePrefix + unsignedNumeral + positiveSuffix;
1807     }
1808 
1809     /*
1810      * Add the locale specific negative prefixes and suffixes to the pattern
1811      */
addNegativeSign(String unsignedNumeral)1812     private String addNegativeSign(String unsignedNumeral) {
1813         String negativePrefix = "";
1814         String negativeSuffix = "";
1815         if (!decimalFormat.getNegativePrefix().isEmpty()) {
1816             negativePrefix = "\\Q" + decimalFormat.getNegativePrefix() + "\\E";
1817         }
1818         if (!decimalFormat.getNegativeSuffix().isEmpty()) {
1819             negativeSuffix = "\\Q" + decimalFormat.getNegativeSuffix() + "\\E";
1820         }
1821         return negativePrefix + unsignedNumeral + negativeSuffix;
1822     }
1823 
1824     /*
1825      * Remove locale related information from float String
1826      */
removeLocaleInfoFromFloat(String floatString)1827     private String removeLocaleInfoFromFloat(String floatString) {
1828         // If the token is HexFloat
1829         if (floatString.indexOf('x') != -1 || floatString.indexOf('X') != -1) {
1830             return floatString;
1831         }
1832 
1833         // If the token is scientific notation
1834         int exponentIndex;
1835         if ((exponentIndex = floatString.indexOf('e')) != -1 || (exponentIndex = floatString.indexOf('E')) != -1) {
1836             String decimalNumeralString = floatString.substring(0, exponentIndex);
1837             String exponentString = floatString.substring(exponentIndex + 1, floatString.length());
1838             decimalNumeralString = removeLocaleInfo(decimalNumeralString, float.class);
1839             return decimalNumeralString + "e" + exponentString;
1840         }
1841         return removeLocaleInfo(floatString, float.class);
1842     }
1843 
1844     /*
1845      * Remove the locale specific prefixes, group separators, and locale
1846      * specific suffixes from input string
1847      */
removeLocaleInfo(String token, Class<?> type)1848     private String removeLocaleInfo(String token, Class<?> type) {
1849         DecimalFormatSymbols dfs = decimalFormat.getDecimalFormatSymbols();
1850 
1851         StringBuilder tokenBuilder = new StringBuilder(token);
1852         boolean negative = removeLocaleSign(tokenBuilder);
1853         // Remove group separator
1854         String groupSeparator = String.valueOf(dfs.getGroupingSeparator());
1855         int separatorIndex;
1856         while ((separatorIndex = tokenBuilder.indexOf(groupSeparator)) != -1) {
1857             tokenBuilder.delete(separatorIndex, separatorIndex + 1);
1858         }
1859         // Remove decimal separator
1860         String decimalSeparator = String.valueOf(dfs.getDecimalSeparator());
1861         separatorIndex = tokenBuilder.indexOf(decimalSeparator);
1862         StringBuilder result = new StringBuilder("");
1863         if (type == int.class) {
1864             for (int i = 0; i < tokenBuilder.length(); i++) {
1865                 if (Character.digit(tokenBuilder.charAt(i), Character.MAX_RADIX) != -1) {
1866                     result.append(tokenBuilder.charAt(i));
1867                 }
1868             }
1869         } else if (type == float.class) {
1870             if (tokenBuilder.toString().equals(dfs.getNaN())) {
1871                 result.append("NaN");
1872             } else if (tokenBuilder.toString().equals(dfs.getInfinity())) {
1873                 result.append("Infinity");
1874             } else {
1875                 for (int i = 0; i < tokenBuilder.length(); i++) {
1876                     if (Character.digit(tokenBuilder.charAt(i), 10) != -1) {
1877                         result.append(Character.digit(tokenBuilder.charAt(i), 10));
1878                     }
1879                 }
1880             }
1881         } else {
1882             throw new AssertionError("Unsupported type: " + type);
1883         }
1884         // Token is NaN or Infinity
1885         if (result.length() == 0) {
1886             result = tokenBuilder;
1887         }
1888         if (separatorIndex != -1) {
1889             result.insert(separatorIndex, ".");
1890         }
1891         // If input is negative
1892         if (negative) {
1893             result.insert(0, '-');
1894         }
1895         return result.toString();
1896     }
1897 
1898     /*
1899      * Remove positive and negative sign from the parameter stringBuilder, and
1900      * return whether the input string is negative
1901      */
removeLocaleSign(StringBuilder tokenBuilder)1902     private boolean removeLocaleSign(StringBuilder tokenBuilder) {
1903         String positivePrefix = decimalFormat.getPositivePrefix();
1904         String positiveSuffix = decimalFormat.getPositiveSuffix();
1905         String negativePrefix = decimalFormat.getNegativePrefix();
1906         String negativeSuffix = decimalFormat.getNegativeSuffix();
1907 
1908         if (tokenBuilder.indexOf("+") == 0) {
1909             tokenBuilder.delete(0, 1);
1910         }
1911         if (!positivePrefix.isEmpty() && tokenBuilder.indexOf(positivePrefix) == 0) {
1912             tokenBuilder.delete(0, positivePrefix.length());
1913         }
1914         if (!positiveSuffix.isEmpty() && tokenBuilder.indexOf(positiveSuffix) != -1) {
1915             tokenBuilder.delete(tokenBuilder.length() - positiveSuffix.length(),
1916                                 tokenBuilder.length());
1917         }
1918         boolean negative = false;
1919         if (tokenBuilder.indexOf("-") == 0) {
1920             tokenBuilder.delete(0, 1);
1921             negative = true;
1922         }
1923         if (!negativePrefix.isEmpty() && tokenBuilder.indexOf(negativePrefix) == 0) {
1924             tokenBuilder.delete(0, negativePrefix.length());
1925             negative = true;
1926         }
1927         if (!negativeSuffix.isEmpty() && tokenBuilder.indexOf(negativeSuffix) != -1) {
1928             tokenBuilder.delete(tokenBuilder.length() - negativeSuffix.length(),
1929                                 tokenBuilder.length());
1930             negative = true;
1931         }
1932         return negative;
1933     }
1934 
1935     /*
1936      * Find the prefixed delimiter and suffixed delimiter in the input resource
1937      * and set the start index and end index of Matcher region. If the suffixed
1938      * delimiter does not exist, the end index is set to be end of input.
1939      */
setTokenRegion()1940     private boolean setTokenRegion() {
1941         // The position where token begins
1942         int tokenStartIndex;
1943         // The position where token ends
1944         int tokenEndIndex;
1945         // Use delimiter pattern
1946         matcher.usePattern(delimiter);
1947         matcher.region(findStartIndex, bufferLength);
1948 
1949         tokenStartIndex = findPreDelimiter();
1950         if (setHeadTokenRegion(tokenStartIndex)) {
1951             return true;
1952         }
1953         tokenEndIndex = findDelimiterAfter();
1954         // If the second delimiter is not found
1955         if (tokenEndIndex == -1) {
1956             // Just first Delimiter Exists
1957             if (findStartIndex == bufferLength) {
1958                 return false;
1959             }
1960             tokenEndIndex = bufferLength;
1961             findStartIndex = bufferLength;
1962         }
1963 
1964         matcher.region(tokenStartIndex, tokenEndIndex);
1965         return true;
1966     }
1967 
1968     /*
1969      * Find prefix delimiter
1970      */
findPreDelimiter()1971     private int findPreDelimiter() {
1972         int tokenStartIndex;
1973         boolean findComplete = false;
1974         while (!findComplete) {
1975             if (matcher.find()) {
1976                 findComplete = true;
1977                 // If just delimiter remains
1978                 if (matcher.start() == findStartIndex && matcher.end() == bufferLength) {
1979                     // If more input resource exists
1980                     if (!inputExhausted) {
1981                         readMore();
1982                         resetMatcher();
1983                         findComplete = false;
1984                     }
1985                 }
1986             } else {
1987                 if (!inputExhausted) {
1988                     readMore();
1989                     resetMatcher();
1990                 } else {
1991                     return -1;
1992                 }
1993             }
1994         }
1995         tokenStartIndex = matcher.end();
1996         findStartIndex = tokenStartIndex;
1997         return tokenStartIndex;
1998     }
1999 
2000     /*
2001      * Handle some special cases
2002      */
setHeadTokenRegion(int findIndex)2003     private boolean setHeadTokenRegion(int findIndex) {
2004         int tokenStartIndex;
2005         int tokenEndIndex;
2006         boolean setSuccess = false;
2007         // If no delimiter exists, but something exists in this scanner
2008         if (findIndex == -1 && preStartIndex != bufferLength) {
2009             tokenStartIndex = preStartIndex;
2010             tokenEndIndex = bufferLength;
2011             findStartIndex = bufferLength;
2012             matcher.region(tokenStartIndex, tokenEndIndex);
2013             setSuccess = true;
2014         }
2015         // If the first delimiter of scanner is not at the find start position
2016         if (findIndex != -1 && preStartIndex != matcher.start()) {
2017             tokenStartIndex = preStartIndex;
2018             tokenEndIndex = matcher.start();
2019             findStartIndex = matcher.start();
2020             // set match region and return
2021             matcher.region(tokenStartIndex, tokenEndIndex);
2022             setSuccess = true;
2023         }
2024         return setSuccess;
2025     }
2026 
findDelimiterAfter()2027     private int findDelimiterAfter() {
2028         int tokenEndIndex;
2029         boolean findComplete = false;
2030         while (!findComplete) {
2031             if (matcher.find()) {
2032                 findComplete = true;
2033                 if (matcher.start() == findStartIndex && matcher.start() == matcher.end()) {
2034                     findComplete = false;
2035                 }
2036             } else {
2037                 if (!inputExhausted) {
2038                     readMore();
2039                     resetMatcher();
2040                 } else {
2041                     return -1;
2042                 }
2043             }
2044         }
2045         tokenEndIndex = matcher.start();
2046         findStartIndex = tokenEndIndex;
2047         return tokenEndIndex;
2048     }
2049 
2050     /*
2051      * Read more data from underlying Readable. If nothing is available or I/O
2052      * operation fails, global boolean variable inputExhausted will be set to
2053      * true, otherwise set to false.
2054      */
readMore()2055     private void readMore() {
2056         int oldPosition = buffer.position();
2057         int oldBufferLength = bufferLength;
2058         // Increase capacity if empty space is not enough
2059         if (bufferLength >= buffer.capacity()) {
2060             expandBuffer();
2061         }
2062 
2063         // Read input resource
2064         int readCount;
2065         try {
2066             buffer.limit(buffer.capacity());
2067             buffer.position(oldBufferLength);
2068             while ((readCount = input.read(buffer)) == 0) {
2069                 // nothing to do here
2070             }
2071         } catch (IOException e) {
2072             // Consider the scenario: readable puts 4 chars into
2073             // buffer and then an IOException is thrown out. In this case,
2074             // buffer is actually grown, but readable.read() will never return.
2075             bufferLength = buffer.position();
2076             // Use -1 to record IOException occurring, and no more input can be read.
2077             readCount = -1;
2078             lastIOException = e;
2079         }
2080 
2081         buffer.flip();
2082         buffer.position(oldPosition);
2083         if (readCount == -1) {
2084             inputExhausted = true;
2085         } else {
2086             bufferLength = readCount + bufferLength;
2087         }
2088     }
2089 
2090     // Expand the size of internal buffer.
expandBuffer()2091     private void expandBuffer() {
2092         int oldPosition = buffer.position();
2093         int oldCapacity = buffer.capacity();
2094         int oldLimit = buffer.limit();
2095         int newCapacity = oldCapacity * 2;
2096         char[] newBuffer = new char[newCapacity];
2097         System.arraycopy(buffer.array(), 0, newBuffer, 0, oldLimit);
2098         buffer = CharBuffer.wrap(newBuffer, 0, newCapacity);
2099         buffer.position(oldPosition);
2100         buffer.limit(oldLimit);
2101     }
2102 
2103     /**
2104      * Resets this scanner's delimiter, locale, and radix.
2105      *
2106      * @return this scanner
2107      * @since 1.6
2108      */
reset()2109     public Scanner reset() {
2110         delimiter = DEFAULT_DELIMITER;
2111         setLocale(Locale.getDefault());
2112         currentRadix = DEFAULT_RADIX;
2113         return this;
2114     }
2115 }
2116