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