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