rt/emul/compact/src/main/java/java/util/StringTokenizer.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 26 Feb 2013 16:54:16 +0100
changeset 772 d382dacfd73f
parent 597 emul/compact/src/main/java/java/util/StringTokenizer.java@ee8a922f4268
permissions -rw-r--r--
Moving modules around so the runtime is under one master pom and can be built without building other modules that are in the repository
jaroslav@597
     1
/*
jaroslav@597
     2
 * Copyright (c) 1994, 2004, Oracle and/or its affiliates. All rights reserved.
jaroslav@597
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jaroslav@597
     4
 *
jaroslav@597
     5
 * This code is free software; you can redistribute it and/or modify it
jaroslav@597
     6
 * under the terms of the GNU General Public License version 2 only, as
jaroslav@597
     7
 * published by the Free Software Foundation.  Oracle designates this
jaroslav@597
     8
 * particular file as subject to the "Classpath" exception as provided
jaroslav@597
     9
 * by Oracle in the LICENSE file that accompanied this code.
jaroslav@597
    10
 *
jaroslav@597
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
jaroslav@597
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jaroslav@597
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
jaroslav@597
    14
 * version 2 for more details (a copy is included in the LICENSE file that
jaroslav@597
    15
 * accompanied this code).
jaroslav@597
    16
 *
jaroslav@597
    17
 * You should have received a copy of the GNU General Public License version
jaroslav@597
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
jaroslav@597
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jaroslav@597
    20
 *
jaroslav@597
    21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jaroslav@597
    22
 * or visit www.oracle.com if you need additional information or have any
jaroslav@597
    23
 * questions.
jaroslav@597
    24
 */
jaroslav@597
    25
jaroslav@597
    26
package java.util;
jaroslav@597
    27
jaroslav@597
    28
import java.lang.*;
jaroslav@597
    29
jaroslav@597
    30
/**
jaroslav@597
    31
 * The string tokenizer class allows an application to break a
jaroslav@597
    32
 * string into tokens. The tokenization method is much simpler than
jaroslav@597
    33
 * the one used by the <code>StreamTokenizer</code> class. The
jaroslav@597
    34
 * <code>StringTokenizer</code> methods do not distinguish among
jaroslav@597
    35
 * identifiers, numbers, and quoted strings, nor do they recognize
jaroslav@597
    36
 * and skip comments.
jaroslav@597
    37
 * <p>
jaroslav@597
    38
 * The set of delimiters (the characters that separate tokens) may
jaroslav@597
    39
 * be specified either at creation time or on a per-token basis.
jaroslav@597
    40
 * <p>
jaroslav@597
    41
 * An instance of <code>StringTokenizer</code> behaves in one of two
jaroslav@597
    42
 * ways, depending on whether it was created with the
jaroslav@597
    43
 * <code>returnDelims</code> flag having the value <code>true</code>
jaroslav@597
    44
 * or <code>false</code>:
jaroslav@597
    45
 * <ul>
jaroslav@597
    46
 * <li>If the flag is <code>false</code>, delimiter characters serve to
jaroslav@597
    47
 *     separate tokens. A token is a maximal sequence of consecutive
jaroslav@597
    48
 *     characters that are not delimiters.
jaroslav@597
    49
 * <li>If the flag is <code>true</code>, delimiter characters are themselves
jaroslav@597
    50
 *     considered to be tokens. A token is thus either one delimiter
jaroslav@597
    51
 *     character, or a maximal sequence of consecutive characters that are
jaroslav@597
    52
 *     not delimiters.
jaroslav@597
    53
 * </ul><p>
jaroslav@597
    54
 * A <tt>StringTokenizer</tt> object internally maintains a current
jaroslav@597
    55
 * position within the string to be tokenized. Some operations advance this
jaroslav@597
    56
 * current position past the characters processed.<p>
jaroslav@597
    57
 * A token is returned by taking a substring of the string that was used to
jaroslav@597
    58
 * create the <tt>StringTokenizer</tt> object.
jaroslav@597
    59
 * <p>
jaroslav@597
    60
 * The following is one example of the use of the tokenizer. The code:
jaroslav@597
    61
 * <blockquote><pre>
jaroslav@597
    62
 *     StringTokenizer st = new StringTokenizer("this is a test");
jaroslav@597
    63
 *     while (st.hasMoreTokens()) {
jaroslav@597
    64
 *         System.out.println(st.nextToken());
jaroslav@597
    65
 *     }
jaroslav@597
    66
 * </pre></blockquote>
jaroslav@597
    67
 * <p>
jaroslav@597
    68
 * prints the following output:
jaroslav@597
    69
 * <blockquote><pre>
jaroslav@597
    70
 *     this
jaroslav@597
    71
 *     is
jaroslav@597
    72
 *     a
jaroslav@597
    73
 *     test
jaroslav@597
    74
 * </pre></blockquote>
jaroslav@597
    75
 *
jaroslav@597
    76
 * <p>
jaroslav@597
    77
 * <tt>StringTokenizer</tt> is a legacy class that is retained for
jaroslav@597
    78
 * compatibility reasons although its use is discouraged in new code. It is
jaroslav@597
    79
 * recommended that anyone seeking this functionality use the <tt>split</tt>
jaroslav@597
    80
 * method of <tt>String</tt> or the java.util.regex package instead.
jaroslav@597
    81
 * <p>
jaroslav@597
    82
 * The following example illustrates how the <tt>String.split</tt>
jaroslav@597
    83
 * method can be used to break up a string into its basic tokens:
jaroslav@597
    84
 * <blockquote><pre>
jaroslav@597
    85
 *     String[] result = "this is a test".split("\\s");
jaroslav@597
    86
 *     for (int x=0; x&lt;result.length; x++)
jaroslav@597
    87
 *         System.out.println(result[x]);
jaroslav@597
    88
 * </pre></blockquote>
jaroslav@597
    89
 * <p>
jaroslav@597
    90
 * prints the following output:
jaroslav@597
    91
 * <blockquote><pre>
jaroslav@597
    92
 *     this
jaroslav@597
    93
 *     is
jaroslav@597
    94
 *     a
jaroslav@597
    95
 *     test
jaroslav@597
    96
 * </pre></blockquote>
jaroslav@597
    97
 *
jaroslav@597
    98
 * @author  unascribed
jaroslav@597
    99
 * @see     java.io.StreamTokenizer
jaroslav@597
   100
 * @since   JDK1.0
jaroslav@597
   101
 */
jaroslav@597
   102
public
jaroslav@597
   103
class StringTokenizer implements Enumeration<Object> {
jaroslav@597
   104
    private int currentPosition;
jaroslav@597
   105
    private int newPosition;
jaroslav@597
   106
    private int maxPosition;
jaroslav@597
   107
    private String str;
jaroslav@597
   108
    private String delimiters;
jaroslav@597
   109
    private boolean retDelims;
jaroslav@597
   110
    private boolean delimsChanged;
jaroslav@597
   111
jaroslav@597
   112
    /**
jaroslav@597
   113
     * maxDelimCodePoint stores the value of the delimiter character with the
jaroslav@597
   114
     * highest value. It is used to optimize the detection of delimiter
jaroslav@597
   115
     * characters.
jaroslav@597
   116
     *
jaroslav@597
   117
     * It is unlikely to provide any optimization benefit in the
jaroslav@597
   118
     * hasSurrogates case because most string characters will be
jaroslav@597
   119
     * smaller than the limit, but we keep it so that the two code
jaroslav@597
   120
     * paths remain similar.
jaroslav@597
   121
     */
jaroslav@597
   122
    private int maxDelimCodePoint;
jaroslav@597
   123
jaroslav@597
   124
    /**
jaroslav@597
   125
     * If delimiters include any surrogates (including surrogate
jaroslav@597
   126
     * pairs), hasSurrogates is true and the tokenizer uses the
jaroslav@597
   127
     * different code path. This is because String.indexOf(int)
jaroslav@597
   128
     * doesn't handle unpaired surrogates as a single character.
jaroslav@597
   129
     */
jaroslav@597
   130
    private boolean hasSurrogates = false;
jaroslav@597
   131
jaroslav@597
   132
    /**
jaroslav@597
   133
     * When hasSurrogates is true, delimiters are converted to code
jaroslav@597
   134
     * points and isDelimiter(int) is used to determine if the given
jaroslav@597
   135
     * codepoint is a delimiter.
jaroslav@597
   136
     */
jaroslav@597
   137
    private int[] delimiterCodePoints;
jaroslav@597
   138
jaroslav@597
   139
    /**
jaroslav@597
   140
     * Set maxDelimCodePoint to the highest char in the delimiter set.
jaroslav@597
   141
     */
jaroslav@597
   142
    private void setMaxDelimCodePoint() {
jaroslav@597
   143
        if (delimiters == null) {
jaroslav@597
   144
            maxDelimCodePoint = 0;
jaroslav@597
   145
            return;
jaroslav@597
   146
        }
jaroslav@597
   147
jaroslav@597
   148
        int m = 0;
jaroslav@597
   149
        int c;
jaroslav@597
   150
        int count = 0;
jaroslav@597
   151
        for (int i = 0; i < delimiters.length(); i += Character.charCount(c)) {
jaroslav@597
   152
            c = delimiters.charAt(i);
jaroslav@597
   153
            if (c >= Character.MIN_HIGH_SURROGATE && c <= Character.MAX_LOW_SURROGATE) {
jaroslav@597
   154
                c = delimiters.codePointAt(i);
jaroslav@597
   155
                hasSurrogates = true;
jaroslav@597
   156
            }
jaroslav@597
   157
            if (m < c)
jaroslav@597
   158
                m = c;
jaroslav@597
   159
            count++;
jaroslav@597
   160
        }
jaroslav@597
   161
        maxDelimCodePoint = m;
jaroslav@597
   162
jaroslav@597
   163
        if (hasSurrogates) {
jaroslav@597
   164
            delimiterCodePoints = new int[count];
jaroslav@597
   165
            for (int i = 0, j = 0; i < count; i++, j += Character.charCount(c)) {
jaroslav@597
   166
                c = delimiters.codePointAt(j);
jaroslav@597
   167
                delimiterCodePoints[i] = c;
jaroslav@597
   168
            }
jaroslav@597
   169
        }
jaroslav@597
   170
    }
jaroslav@597
   171
jaroslav@597
   172
    /**
jaroslav@597
   173
     * Constructs a string tokenizer for the specified string. All
jaroslav@597
   174
     * characters in the <code>delim</code> argument are the delimiters
jaroslav@597
   175
     * for separating tokens.
jaroslav@597
   176
     * <p>
jaroslav@597
   177
     * If the <code>returnDelims</code> flag is <code>true</code>, then
jaroslav@597
   178
     * the delimiter characters are also returned as tokens. Each
jaroslav@597
   179
     * delimiter is returned as a string of length one. If the flag is
jaroslav@597
   180
     * <code>false</code>, the delimiter characters are skipped and only
jaroslav@597
   181
     * serve as separators between tokens.
jaroslav@597
   182
     * <p>
jaroslav@597
   183
     * Note that if <tt>delim</tt> is <tt>null</tt>, this constructor does
jaroslav@597
   184
     * not throw an exception. However, trying to invoke other methods on the
jaroslav@597
   185
     * resulting <tt>StringTokenizer</tt> may result in a
jaroslav@597
   186
     * <tt>NullPointerException</tt>.
jaroslav@597
   187
     *
jaroslav@597
   188
     * @param   str            a string to be parsed.
jaroslav@597
   189
     * @param   delim          the delimiters.
jaroslav@597
   190
     * @param   returnDelims   flag indicating whether to return the delimiters
jaroslav@597
   191
     *                         as tokens.
jaroslav@597
   192
     * @exception NullPointerException if str is <CODE>null</CODE>
jaroslav@597
   193
     */
jaroslav@597
   194
    public StringTokenizer(String str, String delim, boolean returnDelims) {
jaroslav@597
   195
        currentPosition = 0;
jaroslav@597
   196
        newPosition = -1;
jaroslav@597
   197
        delimsChanged = false;
jaroslav@597
   198
        this.str = str;
jaroslav@597
   199
        maxPosition = str.length();
jaroslav@597
   200
        delimiters = delim;
jaroslav@597
   201
        retDelims = returnDelims;
jaroslav@597
   202
        setMaxDelimCodePoint();
jaroslav@597
   203
    }
jaroslav@597
   204
jaroslav@597
   205
    /**
jaroslav@597
   206
     * Constructs a string tokenizer for the specified string. The
jaroslav@597
   207
     * characters in the <code>delim</code> argument are the delimiters
jaroslav@597
   208
     * for separating tokens. Delimiter characters themselves will not
jaroslav@597
   209
     * be treated as tokens.
jaroslav@597
   210
     * <p>
jaroslav@597
   211
     * Note that if <tt>delim</tt> is <tt>null</tt>, this constructor does
jaroslav@597
   212
     * not throw an exception. However, trying to invoke other methods on the
jaroslav@597
   213
     * resulting <tt>StringTokenizer</tt> may result in a
jaroslav@597
   214
     * <tt>NullPointerException</tt>.
jaroslav@597
   215
     *
jaroslav@597
   216
     * @param   str     a string to be parsed.
jaroslav@597
   217
     * @param   delim   the delimiters.
jaroslav@597
   218
     * @exception NullPointerException if str is <CODE>null</CODE>
jaroslav@597
   219
     */
jaroslav@597
   220
    public StringTokenizer(String str, String delim) {
jaroslav@597
   221
        this(str, delim, false);
jaroslav@597
   222
    }
jaroslav@597
   223
jaroslav@597
   224
    /**
jaroslav@597
   225
     * Constructs a string tokenizer for the specified string. The
jaroslav@597
   226
     * tokenizer uses the default delimiter set, which is
jaroslav@597
   227
     * <code>"&nbsp;&#92;t&#92;n&#92;r&#92;f"</code>: the space character,
jaroslav@597
   228
     * the tab character, the newline character, the carriage-return character,
jaroslav@597
   229
     * and the form-feed character. Delimiter characters themselves will
jaroslav@597
   230
     * not be treated as tokens.
jaroslav@597
   231
     *
jaroslav@597
   232
     * @param   str   a string to be parsed.
jaroslav@597
   233
     * @exception NullPointerException if str is <CODE>null</CODE>
jaroslav@597
   234
     */
jaroslav@597
   235
    public StringTokenizer(String str) {
jaroslav@597
   236
        this(str, " \t\n\r\f", false);
jaroslav@597
   237
    }
jaroslav@597
   238
jaroslav@597
   239
    /**
jaroslav@597
   240
     * Skips delimiters starting from the specified position. If retDelims
jaroslav@597
   241
     * is false, returns the index of the first non-delimiter character at or
jaroslav@597
   242
     * after startPos. If retDelims is true, startPos is returned.
jaroslav@597
   243
     */
jaroslav@597
   244
    private int skipDelimiters(int startPos) {
jaroslav@597
   245
        if (delimiters == null)
jaroslav@597
   246
            throw new NullPointerException();
jaroslav@597
   247
jaroslav@597
   248
        int position = startPos;
jaroslav@597
   249
        while (!retDelims && position < maxPosition) {
jaroslav@597
   250
            if (!hasSurrogates) {
jaroslav@597
   251
                char c = str.charAt(position);
jaroslav@597
   252
                if ((c > maxDelimCodePoint) || (delimiters.indexOf(c) < 0))
jaroslav@597
   253
                    break;
jaroslav@597
   254
                position++;
jaroslav@597
   255
            } else {
jaroslav@597
   256
                int c = str.codePointAt(position);
jaroslav@597
   257
                if ((c > maxDelimCodePoint) || !isDelimiter(c)) {
jaroslav@597
   258
                    break;
jaroslav@597
   259
                }
jaroslav@597
   260
                position += Character.charCount(c);
jaroslav@597
   261
            }
jaroslav@597
   262
        }
jaroslav@597
   263
        return position;
jaroslav@597
   264
    }
jaroslav@597
   265
jaroslav@597
   266
    /**
jaroslav@597
   267
     * Skips ahead from startPos and returns the index of the next delimiter
jaroslav@597
   268
     * character encountered, or maxPosition if no such delimiter is found.
jaroslav@597
   269
     */
jaroslav@597
   270
    private int scanToken(int startPos) {
jaroslav@597
   271
        int position = startPos;
jaroslav@597
   272
        while (position < maxPosition) {
jaroslav@597
   273
            if (!hasSurrogates) {
jaroslav@597
   274
                char c = str.charAt(position);
jaroslav@597
   275
                if ((c <= maxDelimCodePoint) && (delimiters.indexOf(c) >= 0))
jaroslav@597
   276
                    break;
jaroslav@597
   277
                position++;
jaroslav@597
   278
            } else {
jaroslav@597
   279
                int c = str.codePointAt(position);
jaroslav@597
   280
                if ((c <= maxDelimCodePoint) && isDelimiter(c))
jaroslav@597
   281
                    break;
jaroslav@597
   282
                position += Character.charCount(c);
jaroslav@597
   283
            }
jaroslav@597
   284
        }
jaroslav@597
   285
        if (retDelims && (startPos == position)) {
jaroslav@597
   286
            if (!hasSurrogates) {
jaroslav@597
   287
                char c = str.charAt(position);
jaroslav@597
   288
                if ((c <= maxDelimCodePoint) && (delimiters.indexOf(c) >= 0))
jaroslav@597
   289
                    position++;
jaroslav@597
   290
            } else {
jaroslav@597
   291
                int c = str.codePointAt(position);
jaroslav@597
   292
                if ((c <= maxDelimCodePoint) && isDelimiter(c))
jaroslav@597
   293
                    position += Character.charCount(c);
jaroslav@597
   294
            }
jaroslav@597
   295
        }
jaroslav@597
   296
        return position;
jaroslav@597
   297
    }
jaroslav@597
   298
jaroslav@597
   299
    private boolean isDelimiter(int codePoint) {
jaroslav@597
   300
        for (int i = 0; i < delimiterCodePoints.length; i++) {
jaroslav@597
   301
            if (delimiterCodePoints[i] == codePoint) {
jaroslav@597
   302
                return true;
jaroslav@597
   303
            }
jaroslav@597
   304
        }
jaroslav@597
   305
        return false;
jaroslav@597
   306
    }
jaroslav@597
   307
jaroslav@597
   308
    /**
jaroslav@597
   309
     * Tests if there are more tokens available from this tokenizer's string.
jaroslav@597
   310
     * If this method returns <tt>true</tt>, then a subsequent call to
jaroslav@597
   311
     * <tt>nextToken</tt> with no argument will successfully return a token.
jaroslav@597
   312
     *
jaroslav@597
   313
     * @return  <code>true</code> if and only if there is at least one token
jaroslav@597
   314
     *          in the string after the current position; <code>false</code>
jaroslav@597
   315
     *          otherwise.
jaroslav@597
   316
     */
jaroslav@597
   317
    public boolean hasMoreTokens() {
jaroslav@597
   318
        /*
jaroslav@597
   319
         * Temporarily store this position and use it in the following
jaroslav@597
   320
         * nextToken() method only if the delimiters haven't been changed in
jaroslav@597
   321
         * that nextToken() invocation.
jaroslav@597
   322
         */
jaroslav@597
   323
        newPosition = skipDelimiters(currentPosition);
jaroslav@597
   324
        return (newPosition < maxPosition);
jaroslav@597
   325
    }
jaroslav@597
   326
jaroslav@597
   327
    /**
jaroslav@597
   328
     * Returns the next token from this string tokenizer.
jaroslav@597
   329
     *
jaroslav@597
   330
     * @return     the next token from this string tokenizer.
jaroslav@597
   331
     * @exception  NoSuchElementException  if there are no more tokens in this
jaroslav@597
   332
     *               tokenizer's string.
jaroslav@597
   333
     */
jaroslav@597
   334
    public String nextToken() {
jaroslav@597
   335
        /*
jaroslav@597
   336
         * If next position already computed in hasMoreElements() and
jaroslav@597
   337
         * delimiters have changed between the computation and this invocation,
jaroslav@597
   338
         * then use the computed value.
jaroslav@597
   339
         */
jaroslav@597
   340
jaroslav@597
   341
        currentPosition = (newPosition >= 0 && !delimsChanged) ?
jaroslav@597
   342
            newPosition : skipDelimiters(currentPosition);
jaroslav@597
   343
jaroslav@597
   344
        /* Reset these anyway */
jaroslav@597
   345
        delimsChanged = false;
jaroslav@597
   346
        newPosition = -1;
jaroslav@597
   347
jaroslav@597
   348
        if (currentPosition >= maxPosition)
jaroslav@597
   349
            throw new NoSuchElementException();
jaroslav@597
   350
        int start = currentPosition;
jaroslav@597
   351
        currentPosition = scanToken(currentPosition);
jaroslav@597
   352
        return str.substring(start, currentPosition);
jaroslav@597
   353
    }
jaroslav@597
   354
jaroslav@597
   355
    /**
jaroslav@597
   356
     * Returns the next token in this string tokenizer's string. First,
jaroslav@597
   357
     * the set of characters considered to be delimiters by this
jaroslav@597
   358
     * <tt>StringTokenizer</tt> object is changed to be the characters in
jaroslav@597
   359
     * the string <tt>delim</tt>. Then the next token in the string
jaroslav@597
   360
     * after the current position is returned. The current position is
jaroslav@597
   361
     * advanced beyond the recognized token.  The new delimiter set
jaroslav@597
   362
     * remains the default after this call.
jaroslav@597
   363
     *
jaroslav@597
   364
     * @param      delim   the new delimiters.
jaroslav@597
   365
     * @return     the next token, after switching to the new delimiter set.
jaroslav@597
   366
     * @exception  NoSuchElementException  if there are no more tokens in this
jaroslav@597
   367
     *               tokenizer's string.
jaroslav@597
   368
     * @exception NullPointerException if delim is <CODE>null</CODE>
jaroslav@597
   369
     */
jaroslav@597
   370
    public String nextToken(String delim) {
jaroslav@597
   371
        delimiters = delim;
jaroslav@597
   372
jaroslav@597
   373
        /* delimiter string specified, so set the appropriate flag. */
jaroslav@597
   374
        delimsChanged = true;
jaroslav@597
   375
jaroslav@597
   376
        setMaxDelimCodePoint();
jaroslav@597
   377
        return nextToken();
jaroslav@597
   378
    }
jaroslav@597
   379
jaroslav@597
   380
    /**
jaroslav@597
   381
     * Returns the same value as the <code>hasMoreTokens</code>
jaroslav@597
   382
     * method. It exists so that this class can implement the
jaroslav@597
   383
     * <code>Enumeration</code> interface.
jaroslav@597
   384
     *
jaroslav@597
   385
     * @return  <code>true</code> if there are more tokens;
jaroslav@597
   386
     *          <code>false</code> otherwise.
jaroslav@597
   387
     * @see     java.util.Enumeration
jaroslav@597
   388
     * @see     java.util.StringTokenizer#hasMoreTokens()
jaroslav@597
   389
     */
jaroslav@597
   390
    public boolean hasMoreElements() {
jaroslav@597
   391
        return hasMoreTokens();
jaroslav@597
   392
    }
jaroslav@597
   393
jaroslav@597
   394
    /**
jaroslav@597
   395
     * Returns the same value as the <code>nextToken</code> method,
jaroslav@597
   396
     * except that its declared return value is <code>Object</code> rather than
jaroslav@597
   397
     * <code>String</code>. It exists so that this class can implement the
jaroslav@597
   398
     * <code>Enumeration</code> interface.
jaroslav@597
   399
     *
jaroslav@597
   400
     * @return     the next token in the string.
jaroslav@597
   401
     * @exception  NoSuchElementException  if there are no more tokens in this
jaroslav@597
   402
     *               tokenizer's string.
jaroslav@597
   403
     * @see        java.util.Enumeration
jaroslav@597
   404
     * @see        java.util.StringTokenizer#nextToken()
jaroslav@597
   405
     */
jaroslav@597
   406
    public Object nextElement() {
jaroslav@597
   407
        return nextToken();
jaroslav@597
   408
    }
jaroslav@597
   409
jaroslav@597
   410
    /**
jaroslav@597
   411
     * Calculates the number of times that this tokenizer's
jaroslav@597
   412
     * <code>nextToken</code> method can be called before it generates an
jaroslav@597
   413
     * exception. The current position is not advanced.
jaroslav@597
   414
     *
jaroslav@597
   415
     * @return  the number of tokens remaining in the string using the current
jaroslav@597
   416
     *          delimiter set.
jaroslav@597
   417
     * @see     java.util.StringTokenizer#nextToken()
jaroslav@597
   418
     */
jaroslav@597
   419
    public int countTokens() {
jaroslav@597
   420
        int count = 0;
jaroslav@597
   421
        int currpos = currentPosition;
jaroslav@597
   422
        while (currpos < maxPosition) {
jaroslav@597
   423
            currpos = skipDelimiters(currpos);
jaroslav@597
   424
            if (currpos >= maxPosition)
jaroslav@597
   425
                break;
jaroslav@597
   426
            currpos = scanToken(currpos);
jaroslav@597
   427
            count++;
jaroslav@597
   428
        }
jaroslav@597
   429
        return count;
jaroslav@597
   430
    }
jaroslav@597
   431
}