001    /* StringCharacterIterator.java -- Iterate over a character range in a string
002       Copyright (C) 1998, 1999, 2001, 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.text;
040    
041    /**
042     * This class iterates over a range of characters in a <code>String</code>.
043     * For a given range of text, a beginning and ending index,
044     * as well as a current index are defined.  These values can be queried
045     * by the methods in this interface.  Additionally, various methods allow
046     * the index to be set.
047     *
048     * @author Aaron M. Renn (arenn@urbanophile.com)
049     * @author Tom Tromey (tromey@cygnus.com)
050     */
051    public final class StringCharacterIterator implements CharacterIterator
052    {
053      /**
054       * This is the string to iterate over
055       */
056      private String text;
057    
058      /**
059       * This is the value of the start position of the text range.
060       */
061      private int begin;
062    
063      /**
064       * This is the value of the ending position of the text range.
065       */
066      private int end;
067    
068      /**
069       * This is the current value of the scan index.
070       */
071      private int index;
072    
073      /**
074       * This method initializes a new instance of
075       * <code>StringCharacterIterator</code> to iterate over the entire
076       * text of the specified <code>String</code>.  The initial index
077       * value will be set to the first character in the string.
078       *
079       * @param text The <code>String</code> to iterate through (<code>null</code>
080       *             not permitted).
081       *
082       * @throws NullPointerException if <code>text</code> is <code>null</code>.
083       */
084      public StringCharacterIterator (String text)
085      {
086        this (text, 0, text.length (), 0);
087      }
088    
089      /*************************************************************************/
090    
091      /**
092       * This method initializes a new instance of
093       * <code>StringCharacterIterator</code> to iterate over the entire
094       * text of the specified <code>String</code>.  The initial index
095       * value will be set to the specified value.
096       *
097       * @param text The <code>String</code> to iterate through.
098       * @param index The initial index position.
099       */
100      public StringCharacterIterator (String text, int index)
101      {
102        this (text, 0, text.length (), index);
103      }
104    
105      /*************************************************************************/
106    
107      /**
108       * This method initializes a new instance of
109       * <code>StringCharacterIterator</code> that iterates over the text
110       * in a subrange of the specified <code>String</code>.  The
111       * beginning and end of the range are specified by the caller, as is
112       * the initial index position.
113       *
114       * @param text The <code>String</code> to iterate through.
115       * @param begin The beginning position in the character range.
116       * @param end The ending position in the character range.
117       * @param index The initial index position.
118       *
119       * @throws IllegalArgumentException If any of the range values are
120       * invalid.
121       */
122      public StringCharacterIterator (String text, int begin, int end, int index)
123      {
124        int len = text.length ();
125    
126        if ((begin < 0) || (begin > len))
127          throw new IllegalArgumentException ("Bad begin position");
128    
129        if ((end < begin) || (end > len))
130          throw new IllegalArgumentException ("Bad end position");
131    
132        if ((index < begin) || (index > end))
133          throw new IllegalArgumentException ("Bad initial index position");
134    
135        this.text = text;
136        this.begin = begin;
137        this.end = end;
138        this.index = index;
139      }
140    
141      /**
142       * This is a package level constructor that copies the text out of
143       * an existing StringCharacterIterator and resets the beginning and
144       * ending index.
145       *
146       * @param sci The StringCharacterIterator to copy the info from
147       * @param begin The beginning index of the range we are interested in.
148       * @param end The ending index of the range we are interested in.
149       */
150      StringCharacterIterator (StringCharacterIterator sci, int begin, int end)
151      {
152        this (sci.text, begin, end, begin);
153      }
154    
155      /**
156       * This method returns the character at the current index position
157       *
158       * @return The character at the current index position.
159       */
160      public char current ()
161      {
162        return (index < end) ? text.charAt (index) : DONE;
163      }
164    
165      /*************************************************************************/
166    
167      /**
168       * This method increments the current index and then returns the
169       * character at the new index value.  If the index is already at
170       * <code>getEndIndex () - 1</code>, it will not be incremented.
171       *
172       * @return The character at the position of the incremented index
173       * value, or <code>DONE</code> if the index has reached
174       * getEndIndex () - 1.
175       */
176      public char next ()
177      {
178        if (index == end)
179          return DONE;
180    
181        ++index;
182        return current ();
183      }
184    
185      /*************************************************************************/
186    
187      /**
188       * This method decrements the current index and then returns the
189       * character at the new index value.  If the index value is already
190       * at the beginning index, it will not be decremented.
191       *
192       * @return The character at the position of the decremented index
193       * value, or <code>DONE</code> if index was already equal to the
194       * beginning index value.
195       */
196      public char previous ()
197      {
198        if (index == begin)
199          return DONE;
200    
201        --index;
202        return current ();
203      }
204    
205      /*************************************************************************/
206    
207      /**
208       * This method sets the index value to the beginning of the range and returns
209       * the character there.
210       *
211       * @return The character at the beginning of the range, or
212       * <code>DONE</code> if the range is empty.
213       */
214      public char first ()
215      {
216        index = begin;
217        return current ();
218      }
219    
220      /*************************************************************************/
221    
222      /**
223       * This method sets the index value to <code>getEndIndex () - 1</code> and
224       * returns the character there.  If the range is empty, then the index value
225       * will be set equal to the beginning index.
226       *
227       * @return The character at the end of the range, or
228       * <code>DONE</code> if the range is empty.
229       */
230      public char last ()
231      {
232        if (end == begin)
233          return DONE;
234    
235        index = end - 1;
236        return current ();
237      }
238    
239      /*************************************************************************/
240    
241      /**
242       * This method returns the current value of the index.
243       *
244       * @return The current index value
245       */
246      public int getIndex ()
247      {
248        return index;
249      }
250    
251      /*************************************************************************/
252    
253      /**
254       * This method sets the value of the index to the specified value, then
255       * returns the character at that position.
256       *
257       * @param index The new index value.
258       *
259       * @return The character at the new index value or <code>DONE</code>
260       * if the index value is equal to <code>getEndIndex</code>.
261       *
262       * @exception IllegalArgumentException If the specified index is not valid
263       */
264      public char setIndex (int index)
265      {
266        if ((index < begin) || (index > end))
267          throw new IllegalArgumentException ("Bad index specified");
268    
269        this.index = index;
270        return current ();
271      }
272    
273      /*************************************************************************/
274    
275      /**
276       * This method returns the character position of the first character in the
277       * range.
278       *
279       * @return The index of the first character in the range.
280       */
281      public int getBeginIndex ()
282      {
283        return begin;
284      }
285    
286      /*************************************************************************/
287    
288      /**
289       * This method returns the character position of the end of the text range.
290       * This will actually be the index of the first character following the
291       * end of the range.  In the event the text range is empty, this will be
292       * equal to the first character in the range.
293       *
294       * @return The index of the end of the range.
295       */
296      public int getEndIndex ()
297      {
298        return end;
299      }
300    
301      /*************************************************************************/
302    
303      /**
304       * This method creates a copy of this <code>CharacterIterator</code>.
305       *
306       * @return A copy of this <code>CharacterIterator</code>.
307       */
308      public Object clone ()
309      {
310        return new StringCharacterIterator (text, begin, end, index);
311      }
312    
313      /*************************************************************************/
314    
315      /**
316       * This method tests this object for equality againt the specified
317       * object.  This will be true if and only if the specified object:
318       * <p>
319       * <ul>
320       * <li>is not <code>null</code>.</li>
321       * <li>is an instance of <code>StringCharacterIterator</code></li>
322       * <li>has the same text as this object</li>
323       * <li>has the same beginning, ending, and current index as this object.</li>
324       * </ul>
325       *
326       * @param obj The object to test for equality against.
327       *
328       * @return <code>true</code> if the specified object is equal to this
329       * object, <code>false</code> otherwise.
330       */
331      public boolean equals (Object obj)
332      {
333        if (! (obj instanceof StringCharacterIterator))
334          return false;
335    
336        StringCharacterIterator sci = (StringCharacterIterator) obj;
337    
338        return (begin == sci.begin
339                && end == sci.end
340                && index == sci.index
341                && text.equals (sci.text));
342      }
343    
344      /**
345       * Return the hash code for this object.
346       * @return the hash code
347       */
348      public int hashCode()
349      {
350        // Incorporate all the data in a goofy way.
351        return begin ^ end ^ index ^ text.hashCode();
352      }
353    
354      /*************************************************************************/
355    
356      /**
357       * This method allows other classes in java.text to change the value
358       * of the underlying text being iterated through.
359       *
360       * @param text The new <code>String</code> to iterate through.
361       */
362      public void setText (String text)
363      {
364        this.text = text;
365        this.begin = 0;
366        this.end = text.length ();
367        this.index = 0;
368      }
369    }