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