Source code: com/simscomputing/util/MutableString.java
1 // Copyright 2000 Sims Computing, Inc.
2 // Licensed under the GNU Lesser General Public License.
3
4 package com.simscomputing.util;
5
6 import com.simscomputing.SoftwareFaultException;
7 import com.simscomputing.util.Debugger;
8
9 import java.io.Serializable;
10 import java.io.UnsupportedEncodingException;
11 import java.util.ArrayList;
12 import java.util.Locale;
13
14 /**
15 Implements a mutable string class. Implements all constructors and methods from
16 the String and StringBuffer classes. Some additional constructors and methods
17 are also implemented. This class is not thread safe.
18
19 <p>
20
21 <strong>Note:</strong> it has been discovered that the Sun implementation of
22 String and StringBuffer is written such that a StringBuffer can be converted
23 into a String without copying data. Consequently, the String API can
24 be used on a StringBuffer. This revelation may make this MutableString
25 class unnecessary.
26
27 @author David Sims
28 @version $Revision: 1.1.1.1 $ $Date: 2000/02/21 21:22:36 $
29 */
30 public class MutableString implements Serializable {
31
32 /**************/
33 /* attributes */
34 /**************/
35
36 /** The mutable string is stored internally as an ArrayList. */
37 ArrayList stringArray = new ArrayList();
38
39 /****************/
40 /* constructors */
41 /****************/
42
43 /**
44 Constructs an empty MutableString.
45 */
46 public MutableString() {}
47
48 /**
49 Constructs an empty FastString with capacity equal to 'length'.
50
51 @throws NegativeArraySizeException if the length argument is less than 0.
52 */
53 public MutableString(int length) {
54 // make sure the string is big enough to hold 'length' elements
55 stringArray.ensureCapacity(length);
56 } // constructor
57
58 /**
59 Constructs a MutableString that is initialized to 'string'.
60 */
61 public MutableString(String string) {
62 for (int index = 0; index < string.length(); ++index) {
63 stringArray.add(new Character(string.charAt(index)));
64 } // for index
65 } // constructor
66
67 /**
68 Constructs a MutableString that is initialized to 'string'.
69 */
70 /*
71 public MutableString(StringBuffer string) {
72 for (int index = 0; index < string.length(); ++index) {
73 string.add(new Character(string.charAt(index)));
74 } // for index
75 } // constructor
76 */
77
78 /**
79 Constructs a MutableString that is initialized to 'string'.
80 */
81 public MutableString(MutableString string) {
82 // deep copy the string
83 stringArray.ensureCapacity(string.length());
84 for (int index = 0; index < string.length(); ++index) {
85 stringArray.add(string.stringArray.get(index));
86 } // for index
87 } // constructor
88
89 /**
90 Constructs a MutableString that is initialized to 'value'.
91
92 @throws NullPointerException - if 'value' is null
93 */
94 public MutableString(char[] value) {
95 this(value, 0, value.length);
96 } // constructor
97
98 /**
99 Constructs a MutableString that is initialized to
100 the string 'value[offset]..value[offset+count-1]'.
101
102 @throws IndexOutOfBoundsException if the offset and count arguments index
103 characters outside the bounds of the value string.
104 @throws NullPointerException if value is null.
105 */
106 public MutableString(char[] value,
107 int offset,
108 int count) {
109 stringArray.ensureCapacity(count);
110 for (int index = offset; index < offset + count; ++index) {
111 stringArray.add(new Character(value[index]));
112 } // for index
113 } // constructor
114
115 /**
116 Constructs a MutableString that is initialized to
117 the string 'bytes[offset]..bytes[offset+length-1]'
118 using the specified character encoding.
119
120 @throws UnsupportedEncodingException if the named encoding is not supported
121 @throws IndexOutOfBoundsException if the offset and count arguments index characters
122 outside the bounds of the value string.
123 */
124 public MutableString(byte[] bytes,
125 int offset,
126 int length,
127 String enc)
128 throws UnsupportedEncodingException {
129 constructor(bytes, offset, length, enc);
130 } // constructor
131
132 /**
133 Constructs a MutableString that is initialized to 'bytes'
134 using the specified character encoding.
135
136 @throws UnsupportedEncodingException if the named encoding is not supported
137 */
138 public MutableString(byte[] bytes,
139 String enc)
140 throws UnsupportedEncodingException {
141 this(bytes, 0, bytes.length, enc);
142 } // constructor
143
144 /**
145 Constructs a MutableString that is initialized to
146 the string 'bytes[offset]..bytes[offset+length-1]'.
147 */
148 public MutableString(byte[] bytes,
149 int offset,
150 int length) {
151 try {
152 constructor(bytes, offset, length, null);
153 } // try
154 catch (UnsupportedEncodingException e) {
155 throw new SoftwareFaultException("statement should not be reached");
156 } // catch
157 } // constructor
158
159 /**
160 Constructs a MutableString that is initialized to 'bytes'.
161
162 @param byte[] - the MutableString is initialized from these bytes
163 */
164 public MutableString(byte[] bytes) {
165 try {
166 constructor(bytes, 0, bytes.length, null);
167 } // try
168 catch (UnsupportedEncodingException e) {
169 throw new SoftwareFaultException("statement should not be reached");
170 } // catch
171 } // constructor
172
173 /**
174 A method used in constructing the object.
175
176 @param byte[] - initialize the object from these bytes
177 @param int - begin initializing from index 'offset'
178 @param int - take 'length' bytes from 'bytes'
179 @param String - the encoding used
180 */
181 private void constructor(byte[] bytes,
182 int offset,
183 int length,
184 String enc)
185 throws UnsupportedEncodingException {
186 // in case a non-constructor method calls this method
187 stringArray.clear();
188
189 if (enc == null) {
190 // use default encoding
191 stringArray.ensureCapacity(length);
192 for (int index = offset; index < offset + length; ++index) {
193 stringArray.add(new Character( (char) bytes[index]));
194 } // for index
195 } // if
196 else {
197 // use supplied encoding via the String class
198 // note: is there a way we can do encodings directly?
199 String encodedString = new String(bytes, offset, length, enc);
200 for (int index = 0; index < encodedString.length(); ++index) {
201 stringArray.add(new Character( (char) encodedString.charAt(index)));
202 } // for index
203 } // else
204 } // constructor()
205
206 /***********/
207 /* methods */
208 /***********/
209
210 /**
211 Returns the size of the string.
212
213 @return int - the size of the string
214 */
215 public int length() {
216 return stringArray.size();
217 } // length()
218
219 /**
220 Returns string[index].
221
222 @return char - the character at position 'index'
223 */
224 public char charAt(int index) {
225 if (index < 0 || index >= stringArray.size()) {
226 throw new StringIndexOutOfBoundsException();
227 } // if
228
229 return ((Character) stringArray.get(index)).charValue();
230 } // charAt()
231
232 /**
233 Copies MutableString[srcBegin..srcEnd - 1] into 'dst', beginning at offset
234 'dstBegin'.
235
236 @param int - the beginning offset into this object
237 @param int - the ending offset into this object
238 @param char[] - the container for the results
239 @param int - the offset into 'dst' to begin inserting the results
240
241 IndexOutOfBoundsException - If any of the following is true:
242 srcBegin is negative.
243 srcBegin is greater than srcEnd
244 srcEnd is greater than the length of this string
245 dstBegin is negative
246 dstBegin+(srcEnd-srcBegin) is larger than dst.length
247 NullPointerException - if dst is null
248 */
249 public void getChars(int srcBegin,
250 int srcEnd,
251 char[] dst,
252 int dstBegin) {
253 // note: the following 'if' statement would throw a NullPointerException
254 // if 'dst' were null. Checked here anyway; the code is easier to
255 // understand.
256 if (dst == null) {
257 throw new NullPointerException();
258 } // if
259
260 if (srcBegin < 0 || srcBegin > srcEnd || srcEnd > stringArray.size() ||
261 dstBegin < 0 || dstBegin + (srcEnd - srcBegin) > dst.length) {
262 throw new IndexOutOfBoundsException();
263 } // if
264
265 int dstIndex = dstBegin;
266 for (int index = srcBegin; index < srcEnd; ++index) {
267 dst[dstIndex] = ((Character) stringArray.get(index)).charValue();
268 ++dstIndex;
269 } // for index
270 } // getChars()
271
272 /**
273 Returns the MutableString in byte[] form.
274
275 @param String - the encoding to use
276 @return byte[] - the string as bytes using encoding 'enc'
277 */
278 public byte[] getBytes(String enc)
279 throws UnsupportedEncodingException {
280 byte[] result = new byte[stringArray.size()];
281 for (int index = 0; index < stringArray.size(); ++index) {
282 result[index] = (byte) ((Character) stringArray.get(index)).charValue();
283 } // for index
284
285 if (enc != null) {
286 String s = new String(result);
287 return s.getBytes(enc);
288 } // else
289
290 return result;
291 } // getBytes()
292
293 /**
294 Returns the MutableString in byte[] form.
295
296 @return byte[] - the string as bytes
297 */
298 public byte[] getBytes() {
299 try {
300 return getBytes(null);
301 } // try
302 catch (UnsupportedEncodingException e) {
303 throw new SoftwareFaultException("statement should not be reached");
304 } // catch
305 } // getBytes()
306
307 /**
308 Indicates whether 'anObject' is equivalent to this object. 'anObject' must
309 be an instance of MutableString.
310
311 @param Object - the object to compare to this object
312 @return boolean - whether the objects match
313 */
314 public boolean equals(Object anObject) {
315 /*
316 if (anObject instanceof String) {
317 return equals(new MutableString( (String) anObject), true);
318 } // if
319 */
320
321 if (!(anObject instanceof MutableString)) {
322 return false;
323 } // if
324
325 // 'anObject' is a MutableString
326 MutableString aString = (MutableString) anObject;
327 return equals(aString, true);
328 } // equals()
329
330 /**
331 Indicates whether 'anObject' is equivalent to this object.
332
333 @param String - the object to compare to this object
334 @return boolean - whether the objects match
335 */
336 public boolean equals(String anObject) {
337 return equals(new MutableString( (String) anObject), true);
338 } // equals()
339
340 /**
341 Indicates whether 'anotherString' equals this object. Case is ignored.
342
343 @param MutableString - the MutableString to compare to this object
344 @return boolean - whether the MutableStrings match
345 */
346 public boolean equalsIgnoreCase(MutableString anotherString) {
347 return equals(anotherString, false);
348 } // equalsIgnoreCase()
349
350 /**
351 Indicates whether 'anotherString' equals this object. Case is ignored.
352
353 @param String - the string to compare to this object
354 @return boolean - whether the objects match
355 */
356 public boolean equalsIgnoreCase(String anotherString) {
357 return equalsIgnoreCase(new MutableString(anotherString));
358 } // equalsIgnoreCase()
359
360 /**
361 Indicates whether 'anotherString' equals this object.
362
363 @param MutableString - the string to compare to this object
364 @param boolean - whether the comparison should match case
365 @return boolean - whether the objects match
366 */
367 private boolean equals(MutableString anotherString, boolean matchCase) {
368 if (anotherString.stringArray.size() != stringArray.size()) {
369 return false;
370 } // if
371
372 // check if all the characters match
373 char leftChar;
374 char rightChar;
375
376 for (int index = 0; index < stringArray.size(); ++index) {
377 if (matchCase) {
378 leftChar = ((Character) stringArray.get(index)).charValue();
379 rightChar = ((Character) anotherString.stringArray.get(index)).charValue();
380 } // if
381 else {
382 leftChar = Character.toLowerCase( ((Character) stringArray.get(index)).charValue());
383 rightChar = Character.toLowerCase( ((Character) anotherString.stringArray.get(index)).charValue());
384 } // else
385
386 if (leftChar != rightChar) {
387 // at least one pair of characters don't match
388 return false;
389 } // if
390 } // for index
391
392 // all the characters match
393 return true;
394 } // equals()
395
396 /**
397 Returns an integer that represents how the MutableString compares
398 to 'anotherString'. The comparison result is computed as follows:
399
400 If length() != anotherString.length(), result is
401 length() - anotherString.length().
402 Otherwise:
403 If this object exactly matches 'anotherString', result is 0.
404 Otherwise:
405 For the first character position where the characters from the two strings
406 do not match, result is 'string[position] - anotherString[position]'.
407
408 @param MutableString - the string to compare to this object
409 @return int - the comparison result
410 @throws NullPointerException - if anotherString is null.
411 */
412 public int compareTo(MutableString anotherString) {
413 return compareTo(anotherString, true);
414 } // compareTo()
415
416 /**
417 Returns an integer that represents how the MutableString compares
418 to 'anotherString'. The comparison result is computed as follows:
419
420 If length() != anotherString.length(), result is
421 length() - anotherString.length().
422 Otherwise:
423 If this object exactly matches 'anotherString', result is 0.
424 Otherwise:
425 For the first character position where the characters from the two strings
426 do not match, result is 'string[position] - anotherString[position]'.
427
428 @param String - the string to compare to this object
429 @return int - the comparison result
430 @throws NullPointerException - if anotherString is null.
431 */
432 public int compareTo(String anotherString) {
433 return compareTo(new MutableString(anotherString), true);
434 } // compareTo()
435
436 /**
437 Returns an integer that represents how the MutableString compares
438 to 'anotherString'. The comparison result is computed as follows:
439
440 If 'anotherString' is not a String, result is 0.
441 Otherwise:
442 If length() != anotherString.length(), result is
443 length() - anotherString.length().
444 Otherwise:
445 If this object exactly matches 'anotherString', result is 0.
446 Otherwise:
447 For the first character position where the characters from the two strings
448 do not match, result is 'string[position] - anotherString[position]'.
449
450 @param MutableString - the string to compare to this object
451 @return int - the comparison result
452 @throws NullPointerException - if anotherString is null.
453 */
454 public int compareTo(Object anotherString) {
455 if (!(anotherString instanceof MutableString)) {
456 return 0;
457 } // if
458
459 MutableString string = (MutableString) anotherString;
460 return compareTo(string, true);
461 } // compareTo()
462
463 /**
464 Returns an integer that represents how the MutableString compares
465 to 'anotherString'. Caes is ignored. The comparison result is computed as
466 follows:
467
468 If length() != anotherString.length(), result is
469 length() - anotherString.length().
470 Otherwise:
471 If this object exactly matches 'anotherString', result is 0.
472 Otherwise:
473 For the first character position where the characters from the two strings
474 do not match, result is 'string[position] - anotherString[position]'.
475
476 @param MutableString - the string to compare to this object
477 @return int - the comparison result
478 @throws NullPointerException - if anotherString is null.
479 */
480 public int compareToIgnoreCase(MutableString string) {
481 return compareTo(string, false);
482 } // compareToIgnoreCase()
483
484 /**
485 Returns an integer that represents how the MutableString compares
486 to 'anotherString'. Case is ignored. The comparison result is computed as
487 follows:
488
489 If length() != anotherString.length(), result is
490 length() - anotherString.length().
491 Otherwise:
492 If this object exactly matches 'anotherString', result is 0.
493 Otherwise:
494 For the first character position where the characters from the two strings
495 do not match, result is 'string[position] - anotherString[position]'.
496
497 @param String - the string to compare to this object
498 @return int - the comparison result
499 @throws NullPointerException - if anotherString is null.
500 */
501 public int compareToIgnoreCase(String string) {
502 return compareTo(new MutableString(string), false);
503 } // compareToIgnoreCase()
504
505 /**
506 Returns an integer that represents how the MutableString compares
507 to 'anotherString'. The comparison result is computed as follows:
508
509 If length() != anotherString.length(), result is
510 length() - anotherString.length().
511 Otherwise:
512 If this object exactly matches 'anotherString', result is 0.
513 Otherwise:
514 For the first character position where the characters from the two strings
515 do not match, result is 'string[position] - anotherString[position]'.
516
517 @param MutableString - the string to compare to this object
518 @return int - the comparison result
519 @throws NullPointerException - if anotherString is null.
520 */
521 private int compareTo(MutableString anotherString, boolean matchCase) {
522 if (stringArray.size() != anotherString.length()) {
523 return stringArray.size() - anotherString.length();
524 } // if
525
526 // check if all the characters match
527 char leftChar;
528 char rightChar;
529
530 for (int index = 0; index < stringArray.size(); ++index) {
531 if (matchCase) {
532 leftChar = ((Character) stringArray.get(index)).charValue();
533 rightChar = ((Character) anotherString.stringArray.get(index)).charValue();
534 } // if
535 else {
536 leftChar = Character.toLowerCase( ((Character) stringArray.get(index)).charValue());
537 rightChar = Character.toLowerCase( ((Character) anotherString.stringArray.get(index)).charValue());
538 } // else
539
540 if (leftChar != rightChar) {
541 // at least one pair of characters don't match
542 if (matchCase) {
543 return ((Character) stringArray.get(index)).charValue() -
544 ((Character) anotherString.stringArray.get(index)).charValue();
545 } // if
546 else {
547 return leftChar - rightChar;
548 } // else
549 } // if
550 } // for index
551
552 // all the characters match
553 return 0;
554 } // compareTo()
555
556 /**
557 Indicates whether the MutableString[toffset..toffset + len] matches
558 other[ooffset..ooffset + len], ignoring case.
559
560 @param int - the offset into this object
561 @param MutableString - the string to compare against this object
562 @param int - the offset into 'other'
563 @param int - the number of characters to compare
564 @returns boolean - whether the two strings match
565 @throws NullPointerException - if 'other' is null
566 */
567 public boolean regionMatches(int toffset,
568 String other,
569 int ooffset,
570 int len) {
571 return regionMatches(toffset, new MutableString(other), ooffset, len);
572 } // regionMatches()
573
574 /**
575 Indicates whether the MutableString[toffset..toffset + len] matches
576 other[ooffset..ooffset + len], ignoring case.
577
578 @param int - the offset into this object
579 @param MutableString - the string to compare against this object
580 @param int - the offset into 'other'
581 @param int - the number of characters to compare
582 @returns boolean - whether the two strings match
583 @throws NullPointerException - if 'other' is null
584 */
585 public boolean regionMatches(int toffset,
586 MutableString other,
587 int ooffset,
588 int len) {
589 return regionMatches(false, toffset, other, ooffset, len);
590 } // regionMatches()
591
592 /**
593 Indicates whether the MutableString[toffset..toffset + len] matches
594 other[ooffset..ooffset + len], ignoring case.
595
596 @param boolean - whether to ignore case
597 @param int - the offset into this object
598 @param String - the string to compare against this object
599 @param int - the offset into 'other'
600 @param int - the number of characters to compare
601 @returns boolean - whether the two strings match
602 @throws NullPointerException - if 'other' is null
603 */
604 public boolean regionMatches(boolean ignoreCase,
605 int toffset,
606 String other,
607 int ooffset,
608 int len) {
609 return regionMatches(ignoreCase, toffset, new MutableString(other),
610 ooffset, len);
611 } // regionMatches()
612
613 /**
614 Indicates whether the MutableString[toffset..toffset + len] matches
615 'other[ooffset..ooffset + len]', ignoring case.
616
617 @param boolean - whether to ignore case
618 @param int - the offset into this object
619 @param MutableString - the string to compare against this object
620 @param int - the offset into 'other'
621 @param int - the number of characters to compare
622 @returns boolean - whether the two strings match
623 @throws NullPointerException - if 'other' is null
624 */
625 public boolean regionMatches(boolean ignoreCase,
626 int toffset,
627 MutableString other,
628 int ooffset,
629 int len) {
630 if (!(toffset + len <= stringArray.size() && ooffset + len <= other.stringArray.size())) {
631 return false;
632 } // if
633
634 // check if all the characters match
635 char leftChar;
636 char rightChar;
637
638 for (int count = 0; count < len; ++count) {
639 if (!ignoreCase) {
640 leftChar = ((Character) stringArray.get(toffset + count)).charValue();
641 rightChar = ((Character) other.stringArray.get(ooffset + count)).charValue();
642 } // if
643 else {
644 leftChar = Character.toLowerCase( ((Character) stringArray.get(toffset + count)).charValue());
645 rightChar = Character.toLowerCase( ((Character) other.stringArray.get(ooffset +
646 count)).charValue());;
647 } // else
648
649 if (leftChar != rightChar) {
650 // at least one pair of characters don't match
651 return false;
652 } // if
653 } // for index
654
655 // all the characters match
656 return true;
657
658 } // regionMatches()
659
660 /**
661 Indicates whether the MutableString begins with
662 'prefix[toffset..prefix.length() - 1]'.
663
664 @param MutableString - the prefix to check
665 @returns boolean - whether the string begins with 'prefix'
666 @throws NullPointerException - if prefix is null
667 */
668 public boolean startsWith(String prefix,
669 int toffset) {
670 return startsWith(new MutableString(prefix), toffset);
671 } // startsWith()
672
673 /**
674 Indicates whether the MutableString begins with
675 'prefix[toffset..prefix.length() - 1]'.
676
677 @param MutableString - the prefix to check
678 @returns boolean - whether the string begins with 'prefix'
679 @throws NullPointerException - if prefix is null
680 */
681 public boolean startsWith(MutableString prefix,
682 int toffset) {
683 if (stringArray.size() < prefix.stringArray.size()) {
684 return false;
685 } // if
686
687 return regionMatches(0, prefix, toffset, prefix.stringArray.size());
688 } // startsWith()
689
690 /**
691 Indicates whether the MutableString begins with 'prefix'.
692
693 @param String - the prefix to check
694 @returns boolean - whether the string begins with 'prefix'
695 @throws NullPointerException - if prefix is null
696 */
697 public boolean startsWith(String prefix) {
698 return startsWith(new MutableString(prefix));
699 } // startsWith()
700
701 /**
702 Indicates whether the MutableString begins with 'prefix'.
703
704 @param MutableString - the prefix to check
705 @returns boolean - whether the string begins with 'prefix'
706 @throws NullPointerException - if prefix is null
707 */
708 public boolean startsWith(MutableString prefix) {
709 return startsWith(prefix, 0);
710 } // startsWith()
711
712 /**
713 Indicates whether the MutableString ends with 'suffix'.
714
715 @param MutableString - the suffix to check
716 @returns boolean - whether the string ends with 'suffix'
717 @throws NullPointerException - if suffix is null.
718 */
719 public boolean endsWith(MutableString suffix) {
720 if (stringArray.size() < suffix.stringArray.size()) {
721 return false;
722 } // if
723
724 // regionMatches() performs the comparison
725 return regionMatches(stringArray.size() - suffix.stringArray.size(),
726 suffix,
727 0,
728 suffix.stringArray.size());
729 } // endsWith()
730
731 /**
732 Indicates whether the string ends with 'suffix'.
733
734 @param String - the suffix to check
735 @returns boolean - whether the string ends with 'suffix'
736 */
737 public boolean endsWith(String suffix) {
738 return endsWith(new MutableString(suffix));
739 } // endsWith()
740
741 /**
742 Computes a hash code on the string.
743
744 @returns int - s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
745 */
746 public int hashCode() {
747 // s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
748
749 // note: check if 'return new String(ms.toString()).hashCode()' is faster
750 int result = 0;
751 int power;
752
753 for (int index = 0; index < stringArray.size(); ++index) {
754 // compute 31^(length() - index - 1)
755 power = 1;
756 for (int j = 0; j < stringArray.size() - index - 1; ++j) {
757 power *= 31;
758 } // for j
759
760 // result += ((Character) stringArray.get(index)).charValue() * ((int) Math.pow(31.0, ));
761 result += ((Character) stringArray.get(index)).charValue() * power;
762 } // index
763
764 return result;
765 } // hashCode()
766
767 /**
768 Returns the index, if it exists, of the first occurence of 'ch' in
769 the string.
770
771 @param int - the character to search for
772 @return int - the index, if it exists, of the first occurence of 'ch'. If the
773 character does not exist, -1 is returned
774 */
775 public int indexOf(int ch) {
776 return indexOf(ch, 0);
777 } // indexOf()
778
779 /**
780 Returns the index, if it exists, of the first occurence of 'ch' in
781 the string starting at position 'fromIndex' in the string.
782
783 @param int - the character to search for
784 @return int - the index, if it exists, of the first occurence of 'ch'. If the
785 character does not exist, -1 is returned
786 */
787 public int indexOf(int ch,
788 int fromIndex) {
789 for (int index = fromIndex; index < stringArray.size(); ++index) {
790 if ( ((Character) stringArray.get(index)).charValue() == ch) {
791 return index;
792 } // if
793 } // for index
794
795 return -1;
796 } // indexOf()
797
798 /**
799 Returns the index, if it exists, of the last occurence of 'ch' in
800 the string.
801
802 @param ch - the character to search for
803 @return int - the index, if it exists, of the last occurence of 'ch'. If the
804 character does not exist, -1 is returned
805 */
806 public int lastIndexOf(int ch) {
807 return lastIndexOf(ch, 0);
808 } // lastIndexOf()
809
810 /**
811 Returns the index, if it exists, of the last occurence of 'ch' in
812 the string starting at position 'fromIndex' in the string.
813
814 @param char - the character to search for
815 @return int - the index, if it exists, of the last occurence of 'ch'. If the
816 character does not exist, -1 is returned
817 */
818 public int lastIndexOf(int ch,
819 int fromIndex) {
820 int result = -1;
821
822 for (int index = fromIndex; index < stringArray.size(); ++index) {
823 if ( ((Character) stringArray.get(index)).charValue() == ch) {
824 result = index;
825 } // if
826 } // for index
827
828 return result;
829 } // lastIndexOf()
830
831 /**
832 Returns the index, if it exists, of the first occurence of 'str' in
833 the string.
834
835 @param MutableString - the string to search for
836 @return int - the index, if it exists, of the first occurence of 'str'. If the
837 character does not exist, -1 is returned
838 */
839 public int indexOf(MutableString str) {
840 return indexOf(str.toString());
841 } // indexOf()
842
843 /**
844 Returns the index, if it exists, of the first occurence of 'str' in
845 the string.
846
847 @param String - the string to search for
848 @return int - the index, if it exists, of the first occurence of 'str'. If the
849 character does not exist, -1 is returned
850 */
851 public int indexOf(String str) {
852 return indexOf(str, 0, false);
853 } // indexOf()
854
855 /**
856 Returns the index, if it exists, of the first occurence of 'str' in
857 the string beginning at offset 'fromIndex'.
858
859 @param MutableString - the string to search for
860 @return int - the index, if it exists, of the first occurence of 'str'
861 beginning at offset 'fromIndex'. If the character does not exist, -1 is
862 returned
863 */
864 public int indexOf(MutableString str, int fromIndex) {
865 return indexOf(str.toString(), fromIndex);
866 } // indexOf()
867
868 /**
869 Returns the index, if it exists, of the first occurence of 'str' in
870 the string beginning at offset 'fromIndex'.
871
872 @param String - the string to search for
873 @return int - the index, if it exists, of the first occurence of 'str'
874 beginning at offset 'fromIndex'. If the character does not exist, -1 is
875 returned
876 */
877 public int indexOf(String str,
878 int fromIndex) {
879 return indexOf(str, fromIndex, false);
880 } // indexOf()
881
882 /**
883 Returns the index, if it exists, of the last occurence of 'str' in
884 the string.
885
886 @param MutableString - the string to search for
887 @return int - the index, if it exists, of the last occurence of 'str'. If the
888 character does not exist, -1 is returned
889 */
890 public int lastIndexOf(MutableString str) {
891 return lastIndexOf(str.toString());
892 } // lastIndexOf()
893
894 /**
895 Returns the index, if it exists, of the last occurence of 'str' in
896 the string.
897
898 @param String - the string to search for
899 @return int - the index, if it exists, of the last occurence of 'str'. If the
900 character does not exist, -1 is returned
901 */
902 public int lastIndexOf(String str) {
903 return indexOf(str, 0, true);
904 } // lastIndexOf()
905
906 /**
907 Returns the index, if it exists, of the last occurence of 'str' in
908 the string beginning at offset 'fromIndex'.
909
910 @param MutableString - the string to search for
911 @return int - the index, if it exists, of the last occurence of 'str'
912 beginning at offset 'fromIndex'. If the character does not exist, -1 is
913 returned
914 */
915 public int lastIndexOf(MutableString str,
916 int fromIndex) {
917 return lastIndexOf(str.toString(), fromIndex);
918 } // lastIndexOf()
919
920 /**
921 Returns the index, if it exists, of the last occurence of 'str' in
922 the string beginning at offset 'fromIndex'.
923
924 @param String - the string to search for
925 @return int - the index, if it exists, of the last occurence of 'str'
926 beginning at offset 'fromIndex'. If the character does not exist, -1 is
927 returned
928 */
929 public int lastIndexOf(String str,
930 int fromIndex) {
931 return indexOf(str, fromIndex, true);
932 } // lastIndexOf()
933
934 /**
935 Returns the index, if it exists, of the first or last occurence of 'str' in
936 the string beginning at offset 'fromIndex'.
937
938 @param String - the string to search for
939 @param int - the index to begin searching from
940 @param boolean - whether to look for the first or last occurence
941 @return int - the index, if it exists, of the first or last occurence of 'str'
942 beginning at offset 'fromIndex'. If the character does not exist, -1 is
943 returned
944 */
945 private int indexOf(String str, int fromIndex, boolean last) {
946 // note: use a better string matching algorithm
947
948 int matchIndex = -1;
949
950 for (int index = fromIndex; index < stringArray.size(); ++index) {
951 boolean matched = true;
952
953 // check if there's enough room left in 'string' to match 'str'
954 if (index + str.length() < stringArray.size()) {
955 int count = 0;
956 for (int j = 0; j < str.length(); ++j) {
957 if ( ((Character) stringArray.get(index + j)).charValue() !=
958 str.charAt(j)) {
959 matched = false;
960 } // if
961 } // for j
962 } // if
963 else {
964 matched = false;
965 } // else
966
967 if (matched) {
968 if (last) {
969 matchIndex = index;
970 } // if
971 else {
972 return index;
973 } // else
974 } // if
975 } // index
976
977 return matchIndex;
978 } // indexOf()
979
980 /**
981 Returns string[beginIndex..length() - 1] as a new MutableString.
982
983 @returns MutableString - a new MutableString
984 @throws IndexOutOfBoundsException - if beginIndex is negative or larger than
985 the length of this String object.
986 */
987 public MutableString substring(int beginIndex) {
988 return substring(beginIndex, stringArray.size());
989 } // substring()
990
991 /**
992 Returns string[beginIndex..endIndex - 1] as a new MutableString.
993
994 @returns MutableString - a new MutableString
995 @throws IndexOutOfBoundsException - if the beginIndex is negative, or
996 endIndex is larger than the length of this String object, or beginIndex is
997 larger than endIndex.
998 */
999 public MutableString substring(int beginIndex,
1000 int endIndex) {
1001 char[] stringArray = new char[endIndex - beginIndex];
1002
1003 int j = 0;
1004 for (int index = beginIndex; index < endIndex; ++index) {
1005 stringArray[j] = ((Character) this.stringArray.get(index)).charValue();
1006 ++j;
1007 } // for index
1008 return new MutableString(stringArray);
1009 } // substring()
1010
1011 /**
1012 Concatenates 'str' to the MutableString.
1013
1014 @param MutableString - the string to concatenate
1015 @returns MutableString - a reference to this object
1016 @throws NullPointerException - if str is null
1017 */
1018 public MutableString concat(MutableString str) {
1019 return concat(str.toString());
1020 } // concat()
1021
1022 /**
1023 Concatenates 'str' to the MutableString.
1024
1025 @param String - the string to concatenate
1026 @returns MutableString - a reference to this object
1027 @throws NullPointerException - if str is null
1028 */
1029 public MutableString concat(String str) {
1030 // make the string big enough to accommodate the new string
1031 stringArray.ensureCapacity(stringArray.size() + str.length());
1032
1033 // concatenate the new string
1034 for (int index = 0; index < str.length(); ++index) {
1035 stringArray.add(new Character(str.charAt(index)));
1036 } // for index
1037
1038 return this;
1039 } // concat()
1040
1041 /**
1042 Replaces all instances of 'oldChar' with 'newChar'.
1043
1044 @param char - the old character
1045 @param char - the new character that replaces the old character
1046 @returns MutableString - a reference to this object
1047 */
1048 public MutableString replace(char oldChar,
1049 char newChar) {
1050 for (int index = 0; index < stringArray.size(); ++index) {
1051 if ( ((Character) stringArray.get(index)).charValue() == oldChar) {
1052 stringArray.set(index, new Character(newChar));
1053 } // if
1054 } // for index
1055
1056 return this;
1057 } // replace()
1058
1059 /**
1060 Converts all characters in the string to upper case.
1061
1062 @param Locale - convert characters using the specified locale
1063 @returns MutableString - a reference to the string
1064 */
1065 public MutableString toLowerCase(Locale locale) {
1066 if (locale == null) {
1067 // use the default locale
1068
1069 char ch;
1070 Character character;
1071 for (int index = 0; index < stringArray.size(); ++index) {
1072 ch = ((Character) stringArray.get(index)).charValue();
1073 character = new Character(Character.toLowerCase(ch));
1074 stringArray.set(index, character);
1075 } // for index
1076 } // if
1077 else {
1078 // use the specified locale
1079
1080 String s = new String(toString());
1081
1082 // convert to lower case using the specified locale
1083 s.toLowerCase(locale);
1084 // make sure the length of the string didn't change
1085 Debugger.assert(s.length() == length());
1086
1087 Character character;
1088 for (int index = 0; index < stringArray.size(); ++index) {
1089 character = new Character(s.charAt(index));
1090 stringArray.set(index, character);
1091 } // for index
1092 } // else
1093
1094 return this;
1095 } // toLowerCase()
1096
1097 /**
1098 Converts all characters in the string to lower case.
1099
1100 @returns MutableString - a reference to the string
1101 */
1102 public MutableString toLowerCase() {
1103 return toLowerCase(null);
1104 } // toLowerCase()
1105
1106 /**
1107 Converts all characters in the string to upper case.
1108
1109 @param Locale - convert characters using the specified locale
1110 @returns MutableString - a reference to the string
1111 */
1112 public MutableString toUpperCase(Locale locale) {
1113 if (locale == null) {
1114 // use the default locale
1115
1116 char ch;
1117 Character character;
1118 for (int index = 0; index < stringArray.size(); ++index) {
1119 ch = ((Character) stringArray.get(index)).charValue();
1120 character = new Character(Character.toUpperCase(ch));
1121 stringArray.set(index, character);
1122 } // for index
1123 } // if
1124 else {
1125 // use the specified locale
1126
1127 String s = new String(toString());
1128
1129 // convert to lower case using the specified locale
1130 s.toUpperCase(locale);
1131 // make sure the length of the string didn't change
1132 Debugger.assert(s.length() == length());
1133
1134 Character character;
1135 for (int index = 0; index < stringArray.size(); ++index) {
1136 character = new Character(s.charAt(index));
1137 stringArray.set(index, character);
1138 } // for index
1139 } // else
1140
1141 return this;
1142 } // toUpperCase()
1143
1144 /**
1145 Converts all characters in the string to upper case.
1146
1147 @returns MutableString - a reference to the string
1148 */
1149 public MutableString toUpperCase() {
1150 return toUpperCase(null);
1151 } // toUpperCase()
1152
1153 /**
1154 Removes leading and trailing whitespace.
1155
1156 @returns a reference to the object
1157 */
1158 public MutableString trim() {
1159 boolean removed;
1160
1161 // remove leading whitespace
1162 do {
1163 removed = false;
1164 if ( ((Character) stringArray.get(0)).charValue() <= '\u0020') {
1165 stringArray.remove(0);
1166 removed = true;
1167 } // if
1168 } while (removed);
1169
1170 // remove trailing whitespace
1171 removed = true;
1172 while (removed && stringArray.size() > 0) {
1173 removed = false;
1174 if ( ((Character) stringArray.get(stringArray.size() - 1)).charValue() <= '\u0020') {
1175 stringArray.remove(stringArray.size() - 1);
1176 removed = true;
1177 } // if
1178 } // while
1179
1180 return this;
1181 } // trim()
1182
1183 /**
1184 Converts the MutableString to a String
1185
1186 @returns String - the String representation of the MutableString
1187 */
1188 public String toString() {
1189 return new String(toCharArray());
1190 } // toString()
1191
1192 /**
1193 Converts the MutableString to a character string
1194
1195 @returns String - the char[] representation of the MutableString
1196 */
1197 public char[] toCharArray() {
1198 Object[] characters = stringArray.toArray();
1199
1200 char[] chars = new char[characters.length];
1201
1202 for (int index = 0; index < chars.length; ++index) {
1203 chars[index] = ((Character) characters[index]).charValue();
1204 } // for index
1205
1206 return chars;
1207 } // toCharArray()
1208
1209 /**
1210 Creates a MutableString from the string representation of 'obj'.
1211
1212 @param Object - the object to create a string from
1213 @returns MutableString - the MutableString representation of 'obj'
1214 */
1215 public static MutableString valueOf(Object obj) {
1216 if (obj == null) {
1217 return new MutableString("null");
1218 } // if
1219
1220 return new MutableString(obj.toString());
1221 } // valueOf()
1222
1223 /**
1224 Creates a MutableString from the string representation of 'data'.
1225
1226 @param char[] - the object to create a string from
1227 @returns MutableString - the MutableString representation of 'data'
1228 */
1229 public static MutableString valueOf(char[] data) {
1230 return new MutableString(data);
1231 } // valueOf()
1232
1233 /**
1234 Creates a MutableString from the string representation of
1235 'data[offset..offset + count - 1]'.
1236
1237 @param char[] - the object to create a string from
1238 @param int - the offset into 'data' to begin copying from
1239 @param int - the amount of characters to extract from 'data'
1240 @returns MutableString - the MutableString representation of 'data'
1241 @throws NullPointerException - if data is null.
1242 @throws IndexOutOfBoundsException - if offset is negative, or count is
1243 negative, or offset+count is larger than data.length.
1244 */
1245 public static MutableString valueOf(char[] data,
1246 int offset,
1247 int count) {
1248 if (offset < 0 || count < 0 || offset + count >= data.length) {
1249 throw new IndexOutOfBoundsException();
1250 } // if
1251
1252 char[] destination = new char[count];
1253 System.arraycopy(data, offset, destination, 0, count);
1254 return new MutableString(destination);
1255 } // valueOf()
1256
1257 /**
1258 Creates a MutableString from the string representation of
1259 'data[offset..offset + count - 1]'.
1260
1261 @param char[] - the object to create a string from
1262 @param int - the offset into 'data' to begin copying from
1263 @param int - the amount of characters to extract from 'data'
1264 @returns MutableString - the MutableString representation of 'data'
1265 @throws NullPointerException - if data is null.
1266 @throws IndexOutOfBoundsException - if offset is negative, or count is
1267 negative, or offset+count is larger than data.length.
1268 */
1269 public static MutableString copyValueOf(char[] data,
1270 int offset,
1271 int count) {
1272 // how is this different than valueOf(char[], int, int)?
1273 return valueOf(data, offset, count);
1274 } // copyValueOf()
1275
1276 /**
1277 Creates a MutableString from the string representation of 'data'
1278
1279 @param char[] - the object to create a string from
1280 @returns MutableString - the MutableString representation of 'data'
1281 @throws NullPointerException - if data is null.
1282 @throws IndexOutOfBoundsException - if offset is negative, or count is
1283 negative, or offset+count is larger than data.length.
1284 */
1285 public static MutableString copyValueOf(char[] data) {
1286 return valueOf(data, 0, data.length);
1287 } // copyValueOf()
1288
1289 /**
1290 Creates a MutableString from the string representation of 'b'.
1291
1292 @param char[] - the object to create a string from
1293 @returns MutableString - the MutableString representation of 'b'
1294 */
1295 public static MutableString valueOf(boolean b) {
1296 if (b) {
1297 return new MutableString("true");
1298 } // if
1299 else {
1300 return new MutableString("false");
1301 } // else
1302 } // valueOf()
1303
1304 /**
1305 Creates a MutableString from the string representation of 'c'.
1306
1307 @param char[] - the object to create a string from
1308 @returns MutableString - the MutableString representation of 'c'
1309 */
1310 public static MutableString valueOf(char c) {
1311 return new MutableString((new Character(c)).toString());
1312 } // valueOf()
1313
1314 /**
1315 Creates a MutableString from the string representation of 'i'.
1316
1317 @param char[] - the object to create a string from
1318 @returns MutableString - the MutableString representation of 'i'
1319 */
1320 public static MutableString valueOf(int i) {
1321 return new MutableString(Integer.toString(i));
1322 } // valueOf()
1323
1324 /**
1325 Creates a MutableString from the string representation of 'l'.
1326
1327 @param char[] - the object to create a string from
1328 @returns MutableString - the MutableString representation of 'l'
1329 */
1330 public static MutableString valueOf(long l) {
1331 return new MutableString(Long.toString(l));
1332 } // valueOf()
1333
1334 /**
1335 Creates a MutableString from the string representation of 'f'.
1336
1337 @param char[] - the object to create a string from
1338 @returns MutableString - the MutableString representation of 'f'
1339 */
1340 public static MutableString valueOf(float f) {
1341 return new MutableString(Float.toString(f));
1342 } // valueOf()
1343
1344 /**
1345 Creates a MutableString from the string representation of 'd'.
1346
1347 @param char[] - the object to create a string from
1348 @returns MutableString - the MutableString representation of 'd'
1349 */
1350 public static MutableString valueOf(double d) {
1351 return new MutableString(Double.toString(d));
1352 } // valueOf()
1353
1354 /***********************/
1355 /* end of String class */
1356 /***********************/
1357
1358 /**********************/
1359 /* StringBuffer class */
1360 /**********************/
1361
1362 /**
1363 Makes sure the capacity of the object is at least 'minimumCapacity'.
1364
1365 @param int - the minimum capacity
1366 */
1367 public void ensureCapacity(int minimumCapacity) {
1368 stringArray.ensureCapacity(minimumCapacity);
1369 } // ensureCapacity()
1370
1371 /**
1372 Resets the string to string[0..newLength - 1]. If the old string is
1373 shorter, characters are truncated. If the old string is longer, null
1374 characters are inserted.
1375
1376 @param int - the new length of the string
1377 @throws IndexOutOfBoundsException - if 'newLength' is negative
1378 */
1379 public void setLength(int newLength) {
1380 if (newLength < 0) {
1381 throw new IndexOutOfBoundsException();
1382 } // if
1383
1384 if (newLength >= stringArray.size()) {
1385 // string is becoming longer
1386
1387 // note: there's got to be a faster way to do this
1388 for (int index = 0; index < newLength - stringArray.size() + 1; ++index) {
1389 stringArray.add(new Character('\u0000'));
1390 } // for index
1391 } // if
1392 else {
1393 // string is becoming shorter
1394
1395 // note: there's got to be a faster way to do this
1396 for (int index = stringArray.size() - 1; index >= newLength; --index) {
1397 stringArray.remove(index);
1398 } // for index
1399 } // else
1400 } // setLength()
1401
1402 /**
1403 Sets the character at offset 'index' to 'ch'.
1404
1405 @throws IndexOutOfBoundsException - if index is negative or greater than or
1406 equal to length()
1407 */
1408 public void setCharAt(int index,
1409 char ch) {
1410 if (index < 0 || index >= stringArray.size()) {
1411 throw new IndexOutOfBoundsException();
1412 } // if
1413
1414 stringArray.set(index, new Character(ch));
1415 } // setCharAt()
1416
1417 /**
1418 Appends the string representation of 'obj' to the object.
1419
1420 @return MutableString - the object after appending
1421 */
1422 public MutableString append(Object obj) {
1423 append(obj.toString());
1424
1425 return this;
1426 } // append()
1427
1428 /**
1429 Appends 'str' to the object.
1430
1431 @return MutableString - the object after appending
1432 */
1433 public MutableString append(MutableString str) {
1434 concat(str);
1435
1436 return this;
1437 } // append()
1438
1439 /**
1440 Appends 'str' to the object.
1441
1442 @return MutableString - the object after appending
1443 */
1444 public MutableString append(String str) {
1445 concat(str);
1446
1447 return this;
1448 } // append()
1449
1450 /**
1451 Appends 'str' to the object.
1452
1453 @return MutableString - the object after appending
1454 */
1455 public MutableString append(char[] str) {
1456 append(new String(str));
1457
1458 return this;
1459 } // append()
1460
1461 /**
1462 Appends 'str[offset]..str[len-1]' to the object.
1463
1464 @return MutableString - the object after appending
1465 */
1466 public MutableString append(char[] str,
1467 int offset,
1468 int len) {
1469 MutableString ms = MutableString.valueOf(str, offset, len);
1470 append(ms);
1