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