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