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