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