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