001    /* StringTokenizer -- breaks a String into tokens
002       Copyright (C) 1998, 1999, 2001, 2002, 2005  Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package java.util;
040    
041    /**
042     * This class splits a string into tokens.  The caller can set on which
043     * delimiters the string should be split and if the delimiters should be
044     * returned. This is much simpler than {@link java.io.StreamTokenizer}.
045     *
046     * <p>You may change the delimiter set on the fly by calling
047     * nextToken(String).  But the semantic is quite difficult; it even
048     * depends on calling <code>hasMoreTokens()</code>.  You should call
049     * <code>hasMoreTokens()</code> before, otherwise the old delimiters
050     * after the last token are candidates for being returned.
051     *
052     * <p>If you want to get the delimiters, you have to use the three argument
053     * constructor.  The delimiters are returned as token consisting of a
054     * single character.
055     *
056     * @author Jochen Hoenicke
057     * @author Warren Levy (warrenl@cygnus.com)
058     * @see java.io.StreamTokenizer
059     * @status updated to 1.4
060     */
061    public class StringTokenizer implements Enumeration<Object>
062    {
063      // WARNING: StringTokenizer is a CORE class in the bootstrap cycle. See the
064      // comments in vm/reference/java/lang/Runtime for implications of this fact.
065    
066      /**
067       * The position in the str, where we currently are.
068       */
069      private int pos;
070    
071      /**
072       * The string that should be split into tokens.
073       */
074      private final String str;
075    
076      /**
077       * The length of the string.
078       */
079      private final int len;
080    
081      /**
082       * The string containing the delimiter characters.
083       */
084      private String delim;
085    
086      /**
087       * Tells, if we should return the delimiters.
088       */
089      private final boolean retDelims;
090    
091      /**
092       * Creates a new StringTokenizer for the string <code>str</code>,
093       * that should split on the default delimiter set (space, tab,
094       * newline, return and formfeed), and which doesn't return the
095       * delimiters.
096       *
097       * @param str The string to split
098       * @throws NullPointerException if str is null
099       */
100      public StringTokenizer(String str)
101      {
102        this(str, " \t\n\r\f", false);
103      }
104    
105      /**
106       * Create a new StringTokenizer, that splits the given string on
107       * the given delimiter characters.  It doesn't return the delimiter
108       * characters.
109       *
110       * @param str the string to split
111       * @param delim a string containing all delimiter characters
112       * @throws NullPointerException if either argument is null
113       */
114      public StringTokenizer(String str, String delim)
115      {
116        this(str, delim, false);
117      }
118    
119      /**
120       * Create a new StringTokenizer, that splits the given string on
121       * the given delimiter characters.  If you set
122       * <code>returnDelims</code> to <code>true</code>, the delimiter
123       * characters are returned as tokens of their own.  The delimiter
124       * tokens always consist of a single character.
125       *
126       * @param str the string to split
127       * @param delim a string containing all delimiter characters
128       * @param returnDelims tells, if you want to get the delimiters
129       * @throws NullPointerException if str or delim is null
130       */
131      public StringTokenizer(String str, String delim, boolean returnDelims)
132      {
133        len = str.length();
134        this.str = str;
135        this.delim = delim;
136        this.retDelims = returnDelims;
137        this.pos = 0;
138      }
139    
140      /**
141       * Tells if there are more tokens.
142       *
143       * @return true if the next call of nextToken() will succeed
144       */
145      public boolean hasMoreTokens()
146      {
147        if (! retDelims)
148          {
149            while (pos < len && delim.indexOf(str.charAt(pos)) >= 0)
150              pos++;
151          }
152        return pos < len;
153      }
154    
155      /**
156       * Returns the nextToken, changing the delimiter set to the given
157       * <code>delim</code>.  The change of the delimiter set is
158       * permanent, ie. the next call of nextToken(), uses the same
159       * delimiter set.
160       *
161       * @param delim a string containing the new delimiter characters
162       * @return the next token with respect to the new delimiter characters
163       * @throws NoSuchElementException if there are no more tokens
164       * @throws NullPointerException if delim is null
165       */
166      public String nextToken(String delim) throws NoSuchElementException
167      {
168        this.delim = delim;
169        return nextToken();
170      }
171    
172      /**
173       * Returns the nextToken of the string.
174       *
175       * @return the next token with respect to the current delimiter characters
176       * @throws NoSuchElementException if there are no more tokens
177       */
178      public String nextToken() throws NoSuchElementException
179      {
180        if (pos < len && delim.indexOf(str.charAt(pos)) >= 0)
181          {
182            if (retDelims)
183              return str.substring(pos, ++pos);
184            while (++pos < len && delim.indexOf(str.charAt(pos)) >= 0)
185              ;
186          }
187        if (pos < len)
188          {
189            int start = pos;
190            while (++pos < len && delim.indexOf(str.charAt(pos)) < 0)
191              ;
192    
193            return str.substring(start, pos);
194          }
195        throw new NoSuchElementException();
196      }
197    
198      /**
199       * This does the same as hasMoreTokens. This is the
200       * <code>Enumeration</code> interface method.
201       *
202       * @return true, if the next call of nextElement() will succeed
203       * @see #hasMoreTokens()
204       */
205      public boolean hasMoreElements()
206      {
207        return hasMoreTokens();
208      }
209    
210      /**
211       * This does the same as nextTokens. This is the
212       * <code>Enumeration</code> interface method.
213       *
214       * @return the next token with respect to the current delimiter characters
215       * @throws NoSuchElementException if there are no more tokens
216       * @see #nextToken()
217       */
218      public Object nextElement() throws NoSuchElementException
219      {
220        return nextToken();
221      }
222    
223      /**
224       * This counts the number of remaining tokens in the string, with
225       * respect to the current delimiter set.
226       *
227       * @return the number of times <code>nextTokens()</code> will succeed
228       * @see #nextToken()
229       */
230      public int countTokens()
231      {
232        int count = 0;
233        int delimiterCount = 0;
234        boolean tokenFound = false; // Set when a non-delimiter is found
235        int tmpPos = pos;
236    
237        // Note for efficiency, we count up the delimiters rather than check
238        // retDelims every time we encounter one.  That way, we can
239        // just do the conditional once at the end of the method
240        while (tmpPos < len)
241          {
242            if (delim.indexOf(str.charAt(tmpPos++)) >= 0)
243              {
244                if (tokenFound)
245                  {
246                    // Got to the end of a token
247                    count++;
248                    tokenFound = false;
249                  }
250                delimiterCount++; // Increment for this delimiter
251              }
252            else
253              {
254                tokenFound = true;
255                // Get to the end of the token
256                while (tmpPos < len
257                       && delim.indexOf(str.charAt(tmpPos)) < 0)
258                  ++tmpPos;
259              }
260          }
261    
262        // Make sure to count the last token
263        if (tokenFound)
264          count++;
265    
266        // if counting delmiters add them into the token count
267        return retDelims ? count + delimiterCount : count;
268      }
269    } // class StringTokenizer