001    /* 
002     * Copyright (c) Holger Pfaff - http://pfaff.ws
003     *
004     * This software maybe used for any purpose provided the
005     * above copyright notice is retained. It is supplied as is.
006     * No warranty expressed or implied - Use at your own risk.
007     */
008    
009    import java.util.Enumeration;
010    import java.util.Vector;
011    
012    /**
013      * (#)StringSplitter.java
014      * @author   Holger Pfaff
015      * @version   
016      * Behaves much like StringTokenizer except that <code>delimiter</code>
017      * is used as whole as a delimiter instead of single delim characters,
018      * and the 'null space' between two delimiters is honored by default e.g:
019      *
020      * <code>delimiter</code> = "@-@"
021      * <code>string</code> = "one@-@@-@two@-@three@four-five@-@"
022      *
023      * StringTokenizer ->  "one" "two" "three" "four" "five"
024      * StringSplitter ->  "one" "" "two" "three@four-five" ""  or
025      * StringSplitter ->  "one" "two" "three@four-five"   
026      *
027      */
028      
029    public class StringSplitter implements Enumeration {
030    
031      /**
032       * pointer into string
033       */
034      private int curpos = 0;
035      
036      /**
037       * handle strings with zero length between to delims as separate tokens ?
038       */
039      private boolean splitNull;
040      
041      /**
042       * the string to work on
043       */
044      private String string;
045      
046      /**
047       * the delimiter to use
048       */
049      private String delimiter;
050      
051      /**
052       * length of origin string
053       */
054      private int stringlen;
055    
056      /**
057       * length of delimiter
058       */
059      private int delimiterlen;
060            
061      /**
062       * Construct a new StringSplitter. <code>null</code> strings will
063       * be handled as empty ones.
064       *
065       * @param   string   string to split.
066       * @param   delimiter   string to use as delimiter.
067       *
068       */
069      public StringSplitter(String string, String delimiter) {
070        this(string, delimiter, true);
071      }
072      
073      /**
074       * Construct a new StringSplitter. <code>null</code> strings will
075       * be handled as empty ones.
076       *
077       * @param   string   string to split.
078       * @param   delimiter   string to use as delimiter.
079       * @param   splitNull   handle strings with zero length between to delims as separate tokens?.
080       */
081      public StringSplitter(String string, String delimiter, boolean splitNull) {
082        this.string       = string == null ? new String("") : string;
083        this.stringlen    = this.string.length();
084        this.delimiter    = delimiter == null ? new String(" ") : delimiter;
085        this.delimiterlen = this.delimiter.length();
086        this.splitNull    = splitNull;
087      }
088      
089      /**
090       * Tests if there are more tokens/splitter available from this string.
091       */
092      public boolean hasMoreTokens() {
093        return hasMoreTokens(curpos);
094      }
095      
096      /**
097       * Tests if there are more tokens/splitter available from this string.
098       *
099       * @param   pos   position to start from.
100       */
101      public boolean hasMoreTokens(int pos) {
102        return getNextPosition(pos) == -1 ? false : true;
103      }
104      
105      /**
106       * Return index of next position within string. return -1 for none
107       *
108       * @param   pos   position to start from.
109       */
110      public int getNextPosition(int pos) {
111        return getNextPosition(pos, false);
112      }
113      
114      /**
115       * Return index of next position within string. return -1 for none
116       *
117       * @param   pos   position to start from.
118       * @param   modcurpos   should the curpos var be modified ?
119       */
120      private int getNextPosition(int pos, boolean modcurpos) {
121        if(stringlen == 0 || pos > stringlen) {
122          return -1;
123        } else {
124          if(delimiterlen == 0) {
125            return pos == 0 ? stringlen : -1;
126          } else {
127            int end = string.indexOf(delimiter, pos);
128            if(end == -1) end = stringlen;
129            if(end == pos && splitNull == false) {
130              if(modcurpos) curpos += delimiterlen;
131              return getNextPosition(end + delimiterlen); // skip empty token
132            } else {
133              return end;
134            }
135          }
136        }
137      }
138            
139      /**
140       * Returns the next token available from this string or null
141       */
142      public String nextToken() {
143        int beg, end = getNextPosition(curpos, true);
144        if(end == -1) {
145          return null;
146        } else {
147          beg = curpos; curpos = end + delimiterlen;
148          return string.substring(beg, end);
149        }
150      }
151      
152      /**
153       * Returns the remaining String of this string or null
154       */
155      public String remainingString() {
156        return getNextPosition(curpos, false) == -1 ? null : string.substring(curpos);
157      }  
158    
159      /**
160       * Same as hasMoreTokens(). Implements Enumeration interface.
161       */
162      public boolean hasMoreElements() {
163        return hasMoreTokens();
164      }
165    
166      /**
167       * Same as nextToken(). Implements Enumeration interface.
168       */
169      public Object nextElement() {
170        return nextToken();
171      }
172    
173      /**
174       * Utility method to convert this splitter to a String array.
175       * Requires Util.class
176       */
177      public String[] toArray() {
178              curpos = 0; return Util.enum2Array(this);
179            }
180      
181      /**
182       * Utility method to convert this splitter to a Vector of Strings.
183       * Requires Util.class
184       */
185      public Vector toVector() {
186              curpos = 0; return Util.enum2Vector(this);
187            }
188      
189      /**
190       * Utility method to convert this splitter to a new String using
191       * <code>delimiter</code> as separator.
192       * Requires Util.class
193       *
194       * @param   delimiter   string to use as separator.
195       */
196      public String toString(String delimiter) {
197        curpos = 0; return Util.enum2String(this, delimiter);
198      }
199    };