1. /*
  2. * @(#)StringTokenizer.java 1.29 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.util;
  8. import java.lang.*;
  9. /**
  10. * The string tokenizer class allows an application to break a
  11. * string into tokens. The tokenization method is much simpler than
  12. * the one used by the <code>StreamTokenizer</code> class. The
  13. * <code>StringTokenizer</code> methods do not distinguish among
  14. * identifiers, numbers, and quoted strings, nor do they recognize
  15. * and skip comments.
  16. * <p>
  17. * The set of delimiters (the characters that separate tokens) may
  18. * be specified either at creation time or on a per-token basis.
  19. * <p>
  20. * An instance of <code>StringTokenizer</code> behaves in one of two
  21. * ways, depending on whether it was created with the
  22. * <code>returnDelims</code> flag having the value <code>true</code>
  23. * or <code>false</code>:
  24. * <ul>
  25. * <li>If the flag is <code>false</code>, delimiter characters serve to
  26. * separate tokens. A token is a maximal sequence of consecutive
  27. * characters that are not delimiters.
  28. * <li>If the flag is <code>true</code>, delimiter characters are themselves
  29. * considered to be tokens. A token is thus either one delimiter
  30. * character, or a maximal sequence of consecutive characters that are
  31. * not delimiters.
  32. * </ul><p>
  33. * A <tt>StringTokenizer</tt> object internally maintains a current
  34. * position within the string to be tokenized. Some operations advance this
  35. * current position past the characters processed.<p>
  36. * A token is returned by taking a substring of the string that was used to
  37. * create the <tt>StringTokenizer</tt> object.
  38. * <p>
  39. * The following is one example of the use of the tokenizer. The code:
  40. * <blockquote><pre>
  41. * StringTokenizer st = new StringTokenizer("this is a test");
  42. * while (st.hasMoreTokens()) {
  43. * System.out.println(st.nextToken());
  44. * }
  45. * </pre></blockquote>
  46. * <p>
  47. * prints the following output:
  48. * <blockquote><pre>
  49. * this
  50. * is
  51. * a
  52. * test
  53. * </pre></blockquote>
  54. *
  55. * <p>
  56. * <tt>StringTokenizer</tt> is a legacy class that is retained for
  57. * compatibility reasons although its use is discouraged in new code. It is
  58. * recommended that anyone seeking this functionality use the <tt>split</tt>
  59. * method of <tt>String</tt> or the java.util.regex package instead.
  60. * <p>
  61. * The following example illustrates how the <tt>String.split</tt>
  62. * method can be used to break up a string into its basic tokens:
  63. * <blockquote><pre>
  64. * String[] result = "this is a test".split("\\s");
  65. * for (int x=0; x<result.length; x++)
  66. * System.out.println(result[x]);
  67. * </pre></blockquote>
  68. * <p>
  69. * prints the following output:
  70. * <blockquote><pre>
  71. * this
  72. * is
  73. * a
  74. * test
  75. * </pre></blockquote>
  76. *
  77. * @author unascribed
  78. * @version 1.29, 01/23/03
  79. * @see java.io.StreamTokenizer
  80. * @since JDK1.0
  81. */
  82. public
  83. class StringTokenizer implements Enumeration {
  84. private int currentPosition;
  85. private int newPosition;
  86. private int maxPosition;
  87. private String str;
  88. private String delimiters;
  89. private boolean retDelims;
  90. private boolean delimsChanged;
  91. /**
  92. * maxDelimChar stores the value of the delimiter character with the
  93. * highest value. It is used to optimize the detection of delimiter
  94. * characters.
  95. */
  96. private char maxDelimChar;
  97. /**
  98. * Set maxDelimChar to the highest char in the delimiter set.
  99. */
  100. private void setMaxDelimChar() {
  101. if (delimiters == null) {
  102. maxDelimChar = 0;
  103. return;
  104. }
  105. char m = 0;
  106. for (int i = 0; i < delimiters.length(); i++) {
  107. char c = delimiters.charAt(i);
  108. if (m < c)
  109. m = c;
  110. }
  111. maxDelimChar = m;
  112. }
  113. /**
  114. * Constructs a string tokenizer for the specified string. All
  115. * characters in the <code>delim</code> argument are the delimiters
  116. * for separating tokens.
  117. * <p>
  118. * If the <code>returnDelims</code> flag is <code>true</code>, then
  119. * the delimiter characters are also returned as tokens. Each
  120. * delimiter is returned as a string of length one. If the flag is
  121. * <code>false</code>, the delimiter characters are skipped and only
  122. * serve as separators between tokens.
  123. * <p>
  124. * Note that if <tt>delim</tt> is <tt>null</tt>, this constructor does
  125. * not throw an exception. However, trying to invoke other methods on the
  126. * resulting <tt>StringTokenizer</tt> may result in a
  127. * <tt>NullPointerException</tt>.
  128. *
  129. * @param str a string to be parsed.
  130. * @param delim the delimiters.
  131. * @param returnDelims flag indicating whether to return the delimiters
  132. * as tokens.
  133. */
  134. public StringTokenizer(String str, String delim, boolean returnDelims) {
  135. currentPosition = 0;
  136. newPosition = -1;
  137. delimsChanged = false;
  138. this.str = str;
  139. maxPosition = str.length();
  140. delimiters = delim;
  141. retDelims = returnDelims;
  142. setMaxDelimChar();
  143. }
  144. /**
  145. * Constructs a string tokenizer for the specified string. The
  146. * characters in the <code>delim</code> argument are the delimiters
  147. * for separating tokens. Delimiter characters themselves will not
  148. * be treated as tokens.
  149. *
  150. * @param str a string to be parsed.
  151. * @param delim the delimiters.
  152. */
  153. public StringTokenizer(String str, String delim) {
  154. this(str, delim, false);
  155. }
  156. /**
  157. * Constructs a string tokenizer for the specified string. The
  158. * tokenizer uses the default delimiter set, which is
  159. * <code>" \t\n\r\f"</code>: the space character,
  160. * the tab character, the newline character, the carriage-return character,
  161. * and the form-feed character. Delimiter characters themselves will
  162. * not be treated as tokens.
  163. *
  164. * @param str a string to be parsed.
  165. */
  166. public StringTokenizer(String str) {
  167. this(str, " \t\n\r\f", false);
  168. }
  169. /**
  170. * Skips delimiters starting from the specified position. If retDelims
  171. * is false, returns the index of the first non-delimiter character at or
  172. * after startPos. If retDelims is true, startPos is returned.
  173. */
  174. private int skipDelimiters(int startPos) {
  175. if (delimiters == null)
  176. throw new NullPointerException();
  177. int position = startPos;
  178. while (!retDelims && position < maxPosition) {
  179. char c = str.charAt(position);
  180. if ((c > maxDelimChar) || (delimiters.indexOf(c) < 0))
  181. break;
  182. position++;
  183. }
  184. return position;
  185. }
  186. /**
  187. * Skips ahead from startPos and returns the index of the next delimiter
  188. * character encountered, or maxPosition if no such delimiter is found.
  189. */
  190. private int scanToken(int startPos) {
  191. int position = startPos;
  192. while (position < maxPosition) {
  193. char c = str.charAt(position);
  194. if ((c <= maxDelimChar) && (delimiters.indexOf(c) >= 0))
  195. break;
  196. position++;
  197. }
  198. if (retDelims && (startPos == position)) {
  199. char c = str.charAt(position);
  200. if ((c <= maxDelimChar) && (delimiters.indexOf(c) >= 0))
  201. position++;
  202. }
  203. return position;
  204. }
  205. /**
  206. * Tests if there are more tokens available from this tokenizer's string.
  207. * If this method returns <tt>true</tt>, then a subsequent call to
  208. * <tt>nextToken</tt> with no argument will successfully return a token.
  209. *
  210. * @return <code>true</code> if and only if there is at least one token
  211. * in the string after the current position; <code>false</code>
  212. * otherwise.
  213. */
  214. public boolean hasMoreTokens() {
  215. /*
  216. * Temporary store this position and use it in the following
  217. * nextToken() method only if the delimiters have'nt been changed in
  218. * that nextToken() invocation.
  219. */
  220. newPosition = skipDelimiters(currentPosition);
  221. return (newPosition < maxPosition);
  222. }
  223. /**
  224. * Returns the next token from this string tokenizer.
  225. *
  226. * @return the next token from this string tokenizer.
  227. * @exception NoSuchElementException if there are no more tokens in this
  228. * tokenizer's string.
  229. */
  230. public String nextToken() {
  231. /*
  232. * If next position already computed in hasMoreElements() and
  233. * delimiters have changed between the computation and this invocation,
  234. * then use the computed value.
  235. */
  236. currentPosition = (newPosition >= 0 && !delimsChanged) ?
  237. newPosition : skipDelimiters(currentPosition);
  238. /* Reset these anyway */
  239. delimsChanged = false;
  240. newPosition = -1;
  241. if (currentPosition >= maxPosition)
  242. throw new NoSuchElementException();
  243. int start = currentPosition;
  244. currentPosition = scanToken(currentPosition);
  245. return str.substring(start, currentPosition);
  246. }
  247. /**
  248. * Returns the next token in this string tokenizer's string. First,
  249. * the set of characters considered to be delimiters by this
  250. * <tt>StringTokenizer</tt> object is changed to be the characters in
  251. * the string <tt>delim</tt>. Then the next token in the string
  252. * after the current position is returned. The current position is
  253. * advanced beyond the recognized token. The new delimiter set
  254. * remains the default after this call.
  255. *
  256. * @param delim the new delimiters.
  257. * @return the next token, after switching to the new delimiter set.
  258. * @exception NoSuchElementException if there are no more tokens in this
  259. * tokenizer's string.
  260. */
  261. public String nextToken(String delim) {
  262. delimiters = delim;
  263. /* delimiter string specified, so set the appropriate flag. */
  264. delimsChanged = true;
  265. setMaxDelimChar();
  266. return nextToken();
  267. }
  268. /**
  269. * Returns the same value as the <code>hasMoreTokens</code>
  270. * method. It exists so that this class can implement the
  271. * <code>Enumeration</code> interface.
  272. *
  273. * @return <code>true</code> if there are more tokens;
  274. * <code>false</code> otherwise.
  275. * @see java.util.Enumeration
  276. * @see java.util.StringTokenizer#hasMoreTokens()
  277. */
  278. public boolean hasMoreElements() {
  279. return hasMoreTokens();
  280. }
  281. /**
  282. * Returns the same value as the <code>nextToken</code> method,
  283. * except that its declared return value is <code>Object</code> rather than
  284. * <code>String</code>. It exists so that this class can implement the
  285. * <code>Enumeration</code> interface.
  286. *
  287. * @return the next token in the string.
  288. * @exception NoSuchElementException if there are no more tokens in this
  289. * tokenizer's string.
  290. * @see java.util.Enumeration
  291. * @see java.util.StringTokenizer#nextToken()
  292. */
  293. public Object nextElement() {
  294. return nextToken();
  295. }
  296. /**
  297. * Calculates the number of times that this tokenizer's
  298. * <code>nextToken</code> method can be called before it generates an
  299. * exception. The current position is not advanced.
  300. *
  301. * @return the number of tokens remaining in the string using the current
  302. * delimiter set.
  303. * @see java.util.StringTokenizer#nextToken()
  304. */
  305. public int countTokens() {
  306. int count = 0;
  307. int currpos = currentPosition;
  308. while (currpos < maxPosition) {
  309. currpos = skipDelimiters(currpos);
  310. if (currpos >= maxPosition)
  311. break;
  312. currpos = scanToken(currpos);
  313. count++;
  314. }
  315. return count;
  316. }
  317. }