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