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