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