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