source: src/main/java/agents/org/apache/commons/lang/text/StrBuilder.java

Last change on this file was 127, checked in by Wouter Pasman, 6 years ago

#41 ROLL BACK of rev.126 . So this version is equal to rev. 125

File size: 95.5 KB
Line 
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17package agents.org.apache.commons.lang.text;
18
19import java.io.Reader;
20import java.io.Writer;
21import java.util.Collection;
22import java.util.Iterator;
23import java.util.List;
24
25import agents.org.apache.commons.lang.ArrayUtils;
26import agents.org.apache.commons.lang.SystemUtils;
27
28/**
29 * Builds a string from constituent parts providing a more flexible and powerful API
30 * than StringBuffer.
31 * <p>
32 * The main differences from StringBuffer/StringBuilder are:
33 * <ul>
34 * <li>Not synchronized</li>
35 * <li>Not final</li>
36 * <li>Subclasses have direct access to character array</li>
37 * <li>Additional methods
38 * <ul>
39 * <li>appendWithSeparators - adds an array of values, with a separator</li>
40 * <li>appendPadding - adds a length padding characters</li>
41 * <li>appendFixedLength - adds a fixed width field to the builder</li>
42 * <li>toCharArray/getChars - simpler ways to get a range of the character array</li>
43 * <li>delete - delete char or string</li>
44 * <li>replace - search and replace for a char or string</li>
45 * <li>leftString/rightString/midString - substring without exceptions</li>
46 * <li>contains - whether the builder contains a char or string</li>
47 * <li>size/clear/isEmpty - collections style API methods</li>
48 * </ul>
49 * </li>
50 * </ul>
51 * <li>Views
52 * <ul>
53 * <li>asTokenizer - uses the internal buffer as the source of a StrTokenizer</li>
54 * <li>asReader - uses the internal buffer as the source of a Reader</li>
55 * <li>asWriter - allows a Writer to write directly to the internal buffer</li>
56 * </ul>
57 * </li>
58 * </ul>
59 * <p>
60 * The aim has been to provide an API that mimics very closely what StringBuffer
61 * provides, but with additional methods. It should be noted that some edge cases,
62 * with invalid indices or null input, have been altered - see individual methods.
63 * The biggest of these changes is that by default, null will not output the text
64 * 'null'. This can be controlled by a property, {@link #setNullText(String)}.
65 * <p>
66 * Prior to 3.0, this class implemented Cloneable but did not implement the
67 * clone method so could not be used. From 3.0 onwards it no longer implements
68 * the interface.
69 *
70 * @author Apache Software Foundation
71 * @since 2.2
72 * @version $Id: StrBuilder.java 1057349 2011-01-10 20:40:49Z niallp $
73 */
74public class StrBuilder implements Cloneable {
75
76 /**
77 * The extra capacity for new builders.
78 */
79 static final int CAPACITY = 32;
80
81 /**
82 * Required for serialization support.
83 *
84 * @see java.io.Serializable
85 */
86 private static final long serialVersionUID = 7628716375283629643L;
87
88 /** Internal data storage. */
89 protected char[] buffer; // TODO make private?
90 /** Current size of the buffer. */
91 protected int size; // TODO make private?
92 /** The new line. */
93 private String newLine;
94 /** The null text. */
95 private String nullText;
96
97 //-----------------------------------------------------------------------
98 /**
99 * Constructor that creates an empty builder initial capacity 32 characters.
100 */
101 public StrBuilder() {
102 this(CAPACITY);
103 }
104
105 /**
106 * Constructor that creates an empty builder the specified initial capacity.
107 *
108 * @param initialCapacity the initial capacity, zero or less will be converted to 32
109 */
110 public StrBuilder(int initialCapacity) {
111 super();
112 if (initialCapacity <= 0) {
113 initialCapacity = CAPACITY;
114 }
115 buffer = new char[initialCapacity];
116 }
117
118 /**
119 * Constructor that creates a builder from the string, allocating
120 * 32 extra characters for growth.
121 *
122 * @param str the string to copy, null treated as blank string
123 */
124 public StrBuilder(String str) {
125 super();
126 if (str == null) {
127 buffer = new char[CAPACITY];
128 } else {
129 buffer = new char[str.length() + CAPACITY];
130 append(str);
131 }
132 }
133
134 //-----------------------------------------------------------------------
135 /**
136 * Gets the text to be appended when a new line is added.
137 *
138 * @return the new line text, null means use system default
139 */
140 public String getNewLineText() {
141 return newLine;
142 }
143
144 /**
145 * Sets the text to be appended when a new line is added.
146 *
147 * @param newLine the new line text, null means use system default
148 * @return this, to enable chaining
149 */
150 public StrBuilder setNewLineText(String newLine) {
151 this.newLine = newLine;
152 return this;
153 }
154
155 //-----------------------------------------------------------------------
156 /**
157 * Gets the text to be appended when null is added.
158 *
159 * @return the null text, null means no append
160 */
161 public String getNullText() {
162 return nullText;
163 }
164
165 /**
166 * Sets the text to be appended when null is added.
167 *
168 * @param nullText the null text, null means no append
169 * @return this, to enable chaining
170 */
171 public StrBuilder setNullText(String nullText) {
172 if (nullText != null && nullText.length() == 0) {
173 nullText = null;
174 }
175 this.nullText = nullText;
176 return this;
177 }
178
179 //-----------------------------------------------------------------------
180 /**
181 * Gets the length of the string builder.
182 *
183 * @return the length
184 */
185 public int length() {
186 return size;
187 }
188
189 /**
190 * Updates the length of the builder by either dropping the last characters
191 * or adding filler of unicode zero.
192 *
193 * @param length the length to set to, must be zero or positive
194 * @return this, to enable chaining
195 * @throws IndexOutOfBoundsException if the length is negative
196 */
197 public StrBuilder setLength(int length) {
198 if (length < 0) {
199 throw new StringIndexOutOfBoundsException(length);
200 }
201 if (length < size) {
202 size = length;
203 } else if (length > size) {
204 ensureCapacity(length);
205 int oldEnd = size;
206 int newEnd = length;
207 size = length;
208 for (int i = oldEnd; i < newEnd; i++) {
209 buffer[i] = '\0';
210 }
211 }
212 return this;
213 }
214
215 //-----------------------------------------------------------------------
216 /**
217 * Gets the current size of the internal character array buffer.
218 *
219 * @return the capacity
220 */
221 public int capacity() {
222 return buffer.length;
223 }
224
225 /**
226 * Checks the capacity and ensures that it is at least the size specified.
227 *
228 * @param capacity the capacity to ensure
229 * @return this, to enable chaining
230 */
231 public StrBuilder ensureCapacity(int capacity) {
232 if (capacity > buffer.length) {
233 char[] old = buffer;
234 buffer = new char[capacity * 2];
235 System.arraycopy(old, 0, buffer, 0, size);
236 }
237 return this;
238 }
239
240 /**
241 * Minimizes the capacity to the actual length of the string.
242 *
243 * @return this, to enable chaining
244 */
245 public StrBuilder minimizeCapacity() {
246 if (buffer.length > length()) {
247 char[] old = buffer;
248 buffer = new char[length()];
249 System.arraycopy(old, 0, buffer, 0, size);
250 }
251 return this;
252 }
253
254 //-----------------------------------------------------------------------
255 /**
256 * Gets the length of the string builder.
257 * <p>
258 * This method is the same as {@link #length()} and is provided to match the
259 * API of Collections.
260 *
261 * @return the length
262 */
263 public int size() {
264 return size;
265 }
266
267 /**
268 * Checks is the string builder is empty (convenience Collections API style method).
269 * <p>
270 * This method is the same as checking {@link #length()} and is provided to match the
271 * API of Collections.
272 *
273 * @return <code>true</code> if the size is <code>0</code>.
274 */
275 public boolean isEmpty() {
276 return size == 0;
277 }
278
279 /**
280 * Clears the string builder (convenience Collections API style method).
281 * <p>
282 * This method does not reduce the size of the internal character buffer.
283 * To do that, call <code>clear()</code> followed by {@link #minimizeCapacity()}.
284 * <p>
285 * This method is the same as {@link #setLength(int)} called with zero
286 * and is provided to match the API of Collections.
287 *
288 * @return this, to enable chaining
289 */
290 public StrBuilder clear() {
291 size = 0;
292 return this;
293 }
294
295 //-----------------------------------------------------------------------
296 /**
297 * Gets the character at the specified index.
298 *
299 * @see #setCharAt(int, char)
300 * @see #deleteCharAt(int)
301 * @param index the index to retrieve, must be valid
302 * @return the character at the index
303 * @throws IndexOutOfBoundsException if the index is invalid
304 */
305 public char charAt(int index) {
306 if (index < 0 || index >= length()) {
307 throw new StringIndexOutOfBoundsException(index);
308 }
309 return buffer[index];
310 }
311
312 /**
313 * Sets the character at the specified index.
314 *
315 * @see #charAt(int)
316 * @see #deleteCharAt(int)
317 * @param index the index to set
318 * @param ch the new character
319 * @return this, to enable chaining
320 * @throws IndexOutOfBoundsException if the index is invalid
321 */
322 public StrBuilder setCharAt(int index, char ch) {
323 if (index < 0 || index >= length()) {
324 throw new StringIndexOutOfBoundsException(index);
325 }
326 buffer[index] = ch;
327 return this;
328 }
329
330 /**
331 * Deletes the character at the specified index.
332 *
333 * @see #charAt(int)
334 * @see #setCharAt(int, char)
335 * @param index the index to delete
336 * @return this, to enable chaining
337 * @throws IndexOutOfBoundsException if the index is invalid
338 */
339 public StrBuilder deleteCharAt(int index) {
340 if (index < 0 || index >= size) {
341 throw new StringIndexOutOfBoundsException(index);
342 }
343 deleteImpl(index, index + 1, 1);
344 return this;
345 }
346
347 //-----------------------------------------------------------------------
348 /**
349 * Copies the builder's character array into a new character array.
350 *
351 * @return a new array that represents the contents of the builder
352 */
353 public char[] toCharArray() {
354 if (size == 0) {
355 return ArrayUtils.EMPTY_CHAR_ARRAY;
356 }
357 char chars[] = new char[size];
358 System.arraycopy(buffer, 0, chars, 0, size);
359 return chars;
360 }
361
362 /**
363 * Copies part of the builder's character array into a new character array.
364 *
365 * @param startIndex the start index, inclusive, must be valid
366 * @param endIndex the end index, exclusive, must be valid except that
367 * if too large it is treated as end of string
368 * @return a new array that holds part of the contents of the builder
369 * @throws IndexOutOfBoundsException if startIndex is invalid,
370 * or if endIndex is invalid (but endIndex greater than size is valid)
371 */
372 public char[] toCharArray(int startIndex, int endIndex) {
373 endIndex = validateRange(startIndex, endIndex);
374 int len = endIndex - startIndex;
375 if (len == 0) {
376 return ArrayUtils.EMPTY_CHAR_ARRAY;
377 }
378 char chars[] = new char[len];
379 System.arraycopy(buffer, startIndex, chars, 0, len);
380 return chars;
381 }
382
383 /**
384 * Copies the character array into the specified array.
385 *
386 * @param destination the destination array, null will cause an array to be created
387 * @return the input array, unless that was null or too small
388 */
389 public char[] getChars(char[] destination) {
390 int len = length();
391 if (destination == null || destination.length < len) {
392 destination = new char[len];
393 }
394 System.arraycopy(buffer, 0, destination, 0, len);
395 return destination;
396 }
397
398 /**
399 * Copies the character array into the specified array.
400 *
401 * @param startIndex first index to copy, inclusive, must be valid
402 * @param endIndex last index, exclusive, must be valid
403 * @param destination the destination array, must not be null or too small
404 * @param destinationIndex the index to start copying in destination
405 * @throws NullPointerException if the array is null
406 * @throws IndexOutOfBoundsException if any index is invalid
407 */
408 public void getChars(int startIndex, int endIndex, char destination[], int destinationIndex) {
409 if (startIndex < 0) {
410 throw new StringIndexOutOfBoundsException(startIndex);
411 }
412 if (endIndex < 0 || endIndex > length()) {
413 throw new StringIndexOutOfBoundsException(endIndex);
414 }
415 if (startIndex > endIndex) {
416 throw new StringIndexOutOfBoundsException("end < start");
417 }
418 System.arraycopy(buffer, startIndex, destination, destinationIndex, endIndex - startIndex);
419 }
420
421 //-----------------------------------------------------------------------
422 /**
423 * Appends the new line string to this string builder.
424 * <p>
425 * The new line string can be altered using {@link #setNewLineText(String)}.
426 * This might be used to force the output to always use Unix line endings
427 * even when on Windows.
428 *
429 * @return this, to enable chaining
430 */
431 public StrBuilder appendNewLine() {
432 if (newLine == null) {
433 append(SystemUtils.LINE_SEPARATOR);
434 return this;
435 }
436 return append(newLine);
437 }
438
439 /**
440 * Appends the text representing <code>null</code> to this string builder.
441 *
442 * @return this, to enable chaining
443 */
444 public StrBuilder appendNull() {
445 if (nullText == null) {
446 return this;
447 }
448 return append(nullText);
449 }
450
451 /**
452 * Appends an object to this string builder.
453 * Appending null will call {@link #appendNull()}.
454 *
455 * @param obj the object to append
456 * @return this, to enable chaining
457 */
458 public StrBuilder append(Object obj) {
459 if (obj == null) {
460 return appendNull();
461 }
462 return append(obj.toString());
463 }
464
465 /**
466 * Appends a string to this string builder.
467 * Appending null will call {@link #appendNull()}.
468 *
469 * @param str the string to append
470 * @return this, to enable chaining
471 */
472 public StrBuilder append(String str) {
473 if (str == null) {
474 return appendNull();
475 }
476 int strLen = str.length();
477 if (strLen > 0) {
478 int len = length();
479 ensureCapacity(len + strLen);
480 str.getChars(0, strLen, buffer, len);
481 size += strLen;
482 }
483 return this;
484 }
485
486 /**
487 * Appends part of a string to this string builder.
488 * Appending null will call {@link #appendNull()}.
489 *
490 * @param str the string to append
491 * @param startIndex the start index, inclusive, must be valid
492 * @param length the length to append, must be valid
493 * @return this, to enable chaining
494 */
495 public StrBuilder append(String str, int startIndex, int length) {
496 if (str == null) {
497 return appendNull();
498 }
499 if (startIndex < 0 || startIndex > str.length()) {
500 throw new StringIndexOutOfBoundsException("startIndex must be valid");
501 }
502 if (length < 0 || (startIndex + length) > str.length()) {
503 throw new StringIndexOutOfBoundsException("length must be valid");
504 }
505 if (length > 0) {
506 int len = length();
507 ensureCapacity(len + length);
508 str.getChars(startIndex, startIndex + length, buffer, len);
509 size += length;
510 }
511 return this;
512 }
513
514 /**
515 * Appends a string buffer to this string builder.
516 * Appending null will call {@link #appendNull()}.
517 *
518 * @param str the string buffer to append
519 * @return this, to enable chaining
520 */
521 public StrBuilder append(StringBuffer str) {
522 if (str == null) {
523 return appendNull();
524 }
525 int strLen = str.length();
526 if (strLen > 0) {
527 int len = length();
528 ensureCapacity(len + strLen);
529 str.getChars(0, strLen, buffer, len);
530 size += strLen;
531 }
532 return this;
533 }
534
535 /**
536 * Appends part of a string buffer to this string builder.
537 * Appending null will call {@link #appendNull()}.
538 *
539 * @param str the string to append
540 * @param startIndex the start index, inclusive, must be valid
541 * @param length the length to append, must be valid
542 * @return this, to enable chaining
543 */
544 public StrBuilder append(StringBuffer str, int startIndex, int length) {
545 if (str == null) {
546 return appendNull();
547 }
548 if (startIndex < 0 || startIndex > str.length()) {
549 throw new StringIndexOutOfBoundsException("startIndex must be valid");
550 }
551 if (length < 0 || (startIndex + length) > str.length()) {
552 throw new StringIndexOutOfBoundsException("length must be valid");
553 }
554 if (length > 0) {
555 int len = length();
556 ensureCapacity(len + length);
557 str.getChars(startIndex, startIndex + length, buffer, len);
558 size += length;
559 }
560 return this;
561 }
562
563 /**
564 * Appends another string builder to this string builder.
565 * Appending null will call {@link #appendNull()}.
566 *
567 * @param str the string builder to append
568 * @return this, to enable chaining
569 */
570 public StrBuilder append(StrBuilder str) {
571 if (str == null) {
572 return appendNull();
573 }
574 int strLen = str.length();
575 if (strLen > 0) {
576 int len = length();
577 ensureCapacity(len + strLen);
578 System.arraycopy(str.buffer, 0, buffer, len, strLen);
579 size += strLen;
580 }
581 return this;
582 }
583
584 /**
585 * Appends part of a string builder to this string builder.
586 * Appending null will call {@link #appendNull()}.
587 *
588 * @param str the string to append
589 * @param startIndex the start index, inclusive, must be valid
590 * @param length the length to append, must be valid
591 * @return this, to enable chaining
592 */
593 public StrBuilder append(StrBuilder str, int startIndex, int length) {
594 if (str == null) {
595 return appendNull();
596 }
597 if (startIndex < 0 || startIndex > str.length()) {
598 throw new StringIndexOutOfBoundsException("startIndex must be valid");
599 }
600 if (length < 0 || (startIndex + length) > str.length()) {
601 throw new StringIndexOutOfBoundsException("length must be valid");
602 }
603 if (length > 0) {
604 int len = length();
605 ensureCapacity(len + length);
606 str.getChars(startIndex, startIndex + length, buffer, len);
607 size += length;
608 }
609 return this;
610 }
611
612 /**
613 * Appends a char array to the string builder.
614 * Appending null will call {@link #appendNull()}.
615 *
616 * @param chars the char array to append
617 * @return this, to enable chaining
618 */
619 public StrBuilder append(char[] chars) {
620 if (chars == null) {
621 return appendNull();
622 }
623 int strLen = chars.length;
624 if (strLen > 0) {
625 int len = length();
626 ensureCapacity(len + strLen);
627 System.arraycopy(chars, 0, buffer, len, strLen);
628 size += strLen;
629 }
630 return this;
631 }
632
633 /**
634 * Appends a char array to the string builder.
635 * Appending null will call {@link #appendNull()}.
636 *
637 * @param chars the char array to append
638 * @param startIndex the start index, inclusive, must be valid
639 * @param length the length to append, must be valid
640 * @return this, to enable chaining
641 */
642 public StrBuilder append(char[] chars, int startIndex, int length) {
643 if (chars == null) {
644 return appendNull();
645 }
646 if (startIndex < 0 || startIndex > chars.length) {
647 throw new StringIndexOutOfBoundsException("Invalid startIndex: " + length);
648 }
649 if (length < 0 || (startIndex + length) > chars.length) {
650 throw new StringIndexOutOfBoundsException("Invalid length: " + length);
651 }
652 if (length > 0) {
653 int len = length();
654 ensureCapacity(len + length);
655 System.arraycopy(chars, startIndex, buffer, len, length);
656 size += length;
657 }
658 return this;
659 }
660
661 /**
662 * Appends a boolean value to the string builder.
663 *
664 * @param value the value to append
665 * @return this, to enable chaining
666 */
667 public StrBuilder append(boolean value) {
668 if (value) {
669 ensureCapacity(size + 4);
670 buffer[size++] = 't';
671 buffer[size++] = 'r';
672 buffer[size++] = 'u';
673 buffer[size++] = 'e';
674 } else {
675 ensureCapacity(size + 5);
676 buffer[size++] = 'f';
677 buffer[size++] = 'a';
678 buffer[size++] = 'l';
679 buffer[size++] = 's';
680 buffer[size++] = 'e';
681 }
682 return this;
683 }
684
685 /**
686 * Appends a char value to the string builder.
687 *
688 * @param ch the value to append
689 * @return this, to enable chaining
690 */
691 public StrBuilder append(char ch) {
692 int len = length();
693 ensureCapacity(len + 1);
694 buffer[size++] = ch;
695 return this;
696 }
697
698 /**
699 * Appends an int value to the string builder using <code>String.valueOf</code>.
700 *
701 * @param value the value to append
702 * @return this, to enable chaining
703 */
704 public StrBuilder append(int value) {
705 return append(String.valueOf(value));
706 }
707
708 /**
709 * Appends a long value to the string builder using <code>String.valueOf</code>.
710 *
711 * @param value the value to append
712 * @return this, to enable chaining
713 */
714 public StrBuilder append(long value) {
715 return append(String.valueOf(value));
716 }
717
718 /**
719 * Appends a float value to the string builder using <code>String.valueOf</code>.
720 *
721 * @param value the value to append
722 * @return this, to enable chaining
723 */
724 public StrBuilder append(float value) {
725 return append(String.valueOf(value));
726 }
727
728 /**
729 * Appends a double value to the string builder using <code>String.valueOf</code>.
730 *
731 * @param value the value to append
732 * @return this, to enable chaining
733 */
734 public StrBuilder append(double value) {
735 return append(String.valueOf(value));
736 }
737
738 //-----------------------------------------------------------------------
739 /**
740 * Appends an object followed by a new line to this string builder.
741 * Appending null will call {@link #appendNull()}.
742 *
743 * @param obj the object to append
744 * @return this, to enable chaining
745 * @since 2.3
746 */
747 public StrBuilder appendln(Object obj) {
748 return append(obj).appendNewLine();
749 }
750
751 /**
752 * Appends a string followed by a new line to this string builder.
753 * Appending null will call {@link #appendNull()}.
754 *
755 * @param str the string to append
756 * @return this, to enable chaining
757 * @since 2.3
758 */
759 public StrBuilder appendln(String str) {
760 return append(str).appendNewLine();
761 }
762
763 /**
764 * Appends part of a string followed by a new line to this string builder.
765 * Appending null will call {@link #appendNull()}.
766 *
767 * @param str the string to append
768 * @param startIndex the start index, inclusive, must be valid
769 * @param length the length to append, must be valid
770 * @return this, to enable chaining
771 * @since 2.3
772 */
773 public StrBuilder appendln(String str, int startIndex, int length) {
774 return append(str, startIndex, length).appendNewLine();
775 }
776
777 /**
778 * Appends a string buffer followed by a new line to this string builder.
779 * Appending null will call {@link #appendNull()}.
780 *
781 * @param str the string buffer to append
782 * @return this, to enable chaining
783 * @since 2.3
784 */
785 public StrBuilder appendln(StringBuffer str) {
786 return append(str).appendNewLine();
787 }
788
789 /**
790 * Appends part of a string buffer followed by a new line to this string builder.
791 * Appending null will call {@link #appendNull()}.
792 *
793 * @param str the string to append
794 * @param startIndex the start index, inclusive, must be valid
795 * @param length the length to append, must be valid
796 * @return this, to enable chaining
797 * @since 2.3
798 */
799 public StrBuilder appendln(StringBuffer str, int startIndex, int length) {
800 return append(str, startIndex, length).appendNewLine();
801 }
802
803 /**
804 * Appends another string builder followed by a new line to this string builder.
805 * Appending null will call {@link #appendNull()}.
806 *
807 * @param str the string builder to append
808 * @return this, to enable chaining
809 * @since 2.3
810 */
811 public StrBuilder appendln(StrBuilder str) {
812 return append(str).appendNewLine();
813 }
814
815 /**
816 * Appends part of a string builder followed by a new line to this string builder.
817 * Appending null will call {@link #appendNull()}.
818 *
819 * @param str the string to append
820 * @param startIndex the start index, inclusive, must be valid
821 * @param length the length to append, must be valid
822 * @return this, to enable chaining
823 * @since 2.3
824 */
825 public StrBuilder appendln(StrBuilder str, int startIndex, int length) {
826 return append(str, startIndex, length).appendNewLine();
827 }
828
829 /**
830 * Appends a char array followed by a new line to the string builder.
831 * Appending null will call {@link #appendNull()}.
832 *
833 * @param chars the char array to append
834 * @return this, to enable chaining
835 * @since 2.3
836 */
837 public StrBuilder appendln(char[] chars) {
838 return append(chars).appendNewLine();
839 }
840
841 /**
842 * Appends a char array followed by a new line to the string builder.
843 * Appending null will call {@link #appendNull()}.
844 *
845 * @param chars the char array to append
846 * @param startIndex the start index, inclusive, must be valid
847 * @param length the length to append, must be valid
848 * @return this, to enable chaining
849 * @since 2.3
850 */
851 public StrBuilder appendln(char[] chars, int startIndex, int length) {
852 return append(chars, startIndex, length).appendNewLine();
853 }
854
855 /**
856 * Appends a boolean value followed by a new line to the string builder.
857 *
858 * @param value the value to append
859 * @return this, to enable chaining
860 * @since 2.3
861 */
862 public StrBuilder appendln(boolean value) {
863 return append(value).appendNewLine();
864 }
865
866 /**
867 * Appends a char value followed by a new line to the string builder.
868 *
869 * @param ch the value to append
870 * @return this, to enable chaining
871 * @since 2.3
872 */
873 public StrBuilder appendln(char ch) {
874 return append(ch).appendNewLine();
875 }
876
877 /**
878 * Appends an int value followed by a new line to the string builder using <code>String.valueOf</code>.
879 *
880 * @param value the value to append
881 * @return this, to enable chaining
882 * @since 2.3
883 */
884 public StrBuilder appendln(int value) {
885 return append(value).appendNewLine();
886 }
887
888 /**
889 * Appends a long value followed by a new line to the string builder using <code>String.valueOf</code>.
890 *
891 * @param value the value to append
892 * @return this, to enable chaining
893 * @since 2.3
894 */
895 public StrBuilder appendln(long value) {
896 return append(value).appendNewLine();
897 }
898
899 /**
900 * Appends a float value followed by a new line to the string builder using <code>String.valueOf</code>.
901 *
902 * @param value the value to append
903 * @return this, to enable chaining
904 * @since 2.3
905 */
906 public StrBuilder appendln(float value) {
907 return append(value).appendNewLine();
908 }
909
910 /**
911 * Appends a double value followed by a new line to the string builder using <code>String.valueOf</code>.
912 *
913 * @param value the value to append
914 * @return this, to enable chaining
915 * @since 2.3
916 */
917 public StrBuilder appendln(double value) {
918 return append(value).appendNewLine();
919 }
920
921 //-----------------------------------------------------------------------
922 /**
923 * Appends each item in an array to the builder without any separators.
924 * Appending a null array will have no effect.
925 * Each object is appended using {@link #append(Object)}.
926 *
927 * @param array the array to append
928 * @return this, to enable chaining
929 * @since 2.3
930 */
931 public StrBuilder appendAll(Object[] array) {
932 if (array != null && array.length > 0) {
933 for (int i = 0; i < array.length; i++) {
934 append(array[i]);
935 }
936 }
937 return this;
938 }
939
940 /**
941 * Appends each item in a collection to the builder without any separators.
942 * Appending a null collection will have no effect.
943 * Each object is appended using {@link #append(Object)}.
944 *
945 * @param coll the collection to append
946 * @return this, to enable chaining
947 * @since 2.3
948 */
949 public StrBuilder appendAll(Collection coll) {
950 if (coll != null && coll.size() > 0) {
951 Iterator it = coll.iterator();
952 while (it.hasNext()) {
953 append(it.next());
954 }
955 }
956 return this;
957 }
958
959 /**
960 * Appends each item in an iterator to the builder without any separators.
961 * Appending a null iterator will have no effect.
962 * Each object is appended using {@link #append(Object)}.
963 *
964 * @param it the iterator to append
965 * @return this, to enable chaining
966 * @since 2.3
967 */
968 public StrBuilder appendAll(Iterator it) {
969 if (it != null) {
970 while (it.hasNext()) {
971 append(it.next());
972 }
973 }
974 return this;
975 }
976
977 //-----------------------------------------------------------------------
978 /**
979 * Appends an array placing separators between each value, but
980 * not before the first or after the last.
981 * Appending a null array will have no effect.
982 * Each object is appended using {@link #append(Object)}.
983 *
984 * @param array the array to append
985 * @param separator the separator to use, null means no separator
986 * @return this, to enable chaining
987 */
988 public StrBuilder appendWithSeparators(Object[] array, String separator) {
989 if (array != null && array.length > 0) {
990 separator = (separator == null ? "" : separator);
991 append(array[0]);
992 for (int i = 1; i < array.length; i++) {
993 append(separator);
994 append(array[i]);
995 }
996 }
997 return this;
998 }
999
1000 /**
1001 * Appends a collection placing separators between each value, but
1002 * not before the first or after the last.
1003 * Appending a null collection will have no effect.
1004 * Each object is appended using {@link #append(Object)}.
1005 *
1006 * @param coll the collection to append
1007 * @param separator the separator to use, null means no separator
1008 * @return this, to enable chaining
1009 */
1010 public StrBuilder appendWithSeparators(Collection coll, String separator) {
1011 if (coll != null && coll.size() > 0) {
1012 separator = (separator == null ? "" : separator);
1013 Iterator it = coll.iterator();
1014 while (it.hasNext()) {
1015 append(it.next());
1016 if (it.hasNext()) {
1017 append(separator);
1018 }
1019 }
1020 }
1021 return this;
1022 }
1023
1024 /**
1025 * Appends an iterator placing separators between each value, but
1026 * not before the first or after the last.
1027 * Appending a null iterator will have no effect.
1028 * Each object is appended using {@link #append(Object)}.
1029 *
1030 * @param it the iterator to append
1031 * @param separator the separator to use, null means no separator
1032 * @return this, to enable chaining
1033 */
1034 public StrBuilder appendWithSeparators(Iterator it, String separator) {
1035 if (it != null) {
1036 separator = (separator == null ? "" : separator);
1037 while (it.hasNext()) {
1038 append(it.next());
1039 if (it.hasNext()) {
1040 append(separator);
1041 }
1042 }
1043 }
1044 return this;
1045 }
1046
1047 //-----------------------------------------------------------------------
1048 /**
1049 * Appends a separator if the builder is currently non-empty.
1050 * Appending a null separator will have no effect.
1051 * The separator is appended using {@link #append(String)}.
1052 * <p>
1053 * This method is useful for adding a separator each time around the
1054 * loop except the first.
1055 * <pre>
1056 * for (Iterator it = list.iterator(); it.hasNext(); ) {
1057 * appendSeparator(",");
1058 * append(it.next());
1059 * }
1060 * </pre>
1061 * Note that for this simple example, you should use
1062 * {@link #appendWithSeparators(Collection, String)}.
1063 *
1064 * @param separator the separator to use, null means no separator
1065 * @return this, to enable chaining
1066 * @since 2.3
1067 */
1068 public StrBuilder appendSeparator(String separator) {
1069 return appendSeparator(separator, null);
1070 }
1071
1072 /**
1073 * Appends one of both separators to the StrBuilder.
1074 * If the builder is currently empty it will append the defaultIfEmpty-separator
1075 * Otherwise it will append the standard-separator
1076 *
1077 * Appending a null separator will have no effect.
1078 * The separator is appended using {@link #append(String)}.
1079 * <p>
1080 * This method is for example useful for constructing queries
1081 * <pre>
1082 * StrBuilder whereClause = new StrBuilder();
1083 * if(searchCommand.getPriority() != null) {
1084 * whereClause.appendSeparator(" and", " where");
1085 * whereClause.append(" priority = ?")
1086 * }
1087 * if(searchCommand.getComponent() != null) {
1088 * whereClause.appendSeparator(" and", " where");
1089 * whereClause.append(" component = ?")
1090 * }
1091 * selectClause.append(whereClause)
1092 * </pre>
1093 *
1094 * @param standard the separator if builder is not empty, null means no separator
1095 * @param defaultIfEmpty the separator if builder is empty, null means no separator
1096 * @return this, to enable chaining
1097 * @since 2.5
1098 */
1099 public StrBuilder appendSeparator(String standard, String defaultIfEmpty) {
1100 String str = isEmpty() ? defaultIfEmpty : standard;
1101 if (str != null) {
1102 append(str);
1103 }
1104 return this;
1105 }
1106
1107 /**
1108 * Appends a separator if the builder is currently non-empty.
1109 * The separator is appended using {@link #append(char)}.
1110 * <p>
1111 * This method is useful for adding a separator each time around the
1112 * loop except the first.
1113 * <pre>
1114 * for (Iterator it = list.iterator(); it.hasNext(); ) {
1115 * appendSeparator(',');
1116 * append(it.next());
1117 * }
1118 * </pre>
1119 * Note that for this simple example, you should use
1120 * {@link #appendWithSeparators(Collection, String)}.
1121 *
1122 * @param separator the separator to use
1123 * @return this, to enable chaining
1124 * @since 2.3
1125 */
1126 public StrBuilder appendSeparator(char separator) {
1127 if (size() > 0) {
1128 append(separator);
1129 }
1130 return this;
1131 }
1132
1133 /**
1134 * Append one of both separators to the builder
1135 * If the builder is currently empty it will append the defaultIfEmpty-separator
1136 * Otherwise it will append the standard-separator
1137 *
1138 * The separator is appended using {@link #append(char)}.
1139 * @param standard the separator if builder is not empty
1140 * @param defaultIfEmpty the separator if builder is empty
1141 * @return this, to enable chaining
1142 * @since 2.5
1143 */
1144 public StrBuilder appendSeparator(char standard, char defaultIfEmpty) {
1145 if (size() > 0) {
1146 append(standard);
1147 }
1148 else {
1149 append(defaultIfEmpty);
1150 }
1151 return this;
1152 }
1153 /**
1154 * Appends a separator to the builder if the loop index is greater than zero.
1155 * Appending a null separator will have no effect.
1156 * The separator is appended using {@link #append(String)}.
1157 * <p>
1158 * This method is useful for adding a separator each time around the
1159 * loop except the first.
1160 * <pre>
1161 * for (int i = 0; i < list.size(); i++) {
1162 * appendSeparator(",", i);
1163 * append(list.get(i));
1164 * }
1165 * </pre>
1166 * Note that for this simple example, you should use
1167 * {@link #appendWithSeparators(Collection, String)}.
1168 *
1169 * @param separator the separator to use, null means no separator
1170 * @param loopIndex the loop index
1171 * @return this, to enable chaining
1172 * @since 2.3
1173 */
1174 public StrBuilder appendSeparator(String separator, int loopIndex) {
1175 if (separator != null && loopIndex > 0) {
1176 append(separator);
1177 }
1178 return this;
1179 }
1180
1181 /**
1182 * Appends a separator to the builder if the loop index is greater than zero.
1183 * The separator is appended using {@link #append(char)}.
1184 * <p>
1185 * This method is useful for adding a separator each time around the
1186 * loop except the first.
1187 * <pre>
1188 * for (int i = 0; i < list.size(); i++) {
1189 * appendSeparator(",", i);
1190 * append(list.get(i));
1191 * }
1192 * </pre>
1193 * Note that for this simple example, you should use
1194 * {@link #appendWithSeparators(Collection, String)}.
1195 *
1196 * @param separator the separator to use
1197 * @param loopIndex the loop index
1198 * @return this, to enable chaining
1199 * @since 2.3
1200 */
1201 public StrBuilder appendSeparator(char separator, int loopIndex) {
1202 if (loopIndex > 0) {
1203 append(separator);
1204 }
1205 return this;
1206 }
1207
1208 //-----------------------------------------------------------------------
1209 /**
1210 * Appends the pad character to the builder the specified number of times.
1211 *
1212 * @param length the length to append, negative means no append
1213 * @param padChar the character to append
1214 * @return this, to enable chaining
1215 */
1216 public StrBuilder appendPadding(int length, char padChar) {
1217 if (length >= 0) {
1218 ensureCapacity(size + length);
1219 for (int i = 0; i < length; i++) {
1220 buffer[size++] = padChar;
1221 }
1222 }
1223 return this;
1224 }
1225
1226 //-----------------------------------------------------------------------
1227 /**
1228 * Appends an object to the builder padding on the left to a fixed width.
1229 * The <code>toString</code> of the object is used.
1230 * If the object is larger than the length, the left hand side is lost.
1231 * If the object is null, the null text value is used.
1232 *
1233 * @param obj the object to append, null uses null text
1234 * @param width the fixed field width, zero or negative has no effect
1235 * @param padChar the pad character to use
1236 * @return this, to enable chaining
1237 */
1238 public StrBuilder appendFixedWidthPadLeft(Object obj, int width, char padChar) {
1239 if (width > 0) {
1240 ensureCapacity(size + width);
1241 String str = (obj == null ? getNullText() : obj.toString());
1242 if (str == null) {
1243 str = "";
1244 }
1245 int strLen = str.length();
1246 if (strLen >= width) {
1247 str.getChars(strLen - width, strLen, buffer, size);
1248 } else {
1249 int padLen = width - strLen;
1250 for (int i = 0; i < padLen; i++) {
1251 buffer[size + i] = padChar;
1252 }
1253 str.getChars(0, strLen, buffer, size + padLen);
1254 }
1255 size += width;
1256 }
1257 return this;
1258 }
1259
1260 /**
1261 * Appends an object to the builder padding on the left to a fixed width.
1262 * The <code>String.valueOf</code> of the <code>int</code> value is used.
1263 * If the formatted value is larger than the length, the left hand side is lost.
1264 *
1265 * @param value the value to append
1266 * @param width the fixed field width, zero or negative has no effect
1267 * @param padChar the pad character to use
1268 * @return this, to enable chaining
1269 */
1270 public StrBuilder appendFixedWidthPadLeft(int value, int width, char padChar) {
1271 return appendFixedWidthPadLeft(String.valueOf(value), width, padChar);
1272 }
1273
1274 /**
1275 * Appends an object to the builder padding on the right to a fixed length.
1276 * The <code>toString</code> of the object is used.
1277 * If the object is larger than the length, the right hand side is lost.
1278 * If the object is null, null text value is used.
1279 *
1280 * @param obj the object to append, null uses null text
1281 * @param width the fixed field width, zero or negative has no effect
1282 * @param padChar the pad character to use
1283 * @return this, to enable chaining
1284 */
1285 public StrBuilder appendFixedWidthPadRight(Object obj, int width, char padChar) {
1286 if (width > 0) {
1287 ensureCapacity(size + width);
1288 String str = (obj == null ? getNullText() : obj.toString());
1289 if (str == null) {
1290 str = "";
1291 }
1292 int strLen = str.length();
1293 if (strLen >= width) {
1294 str.getChars(0, width, buffer, size);
1295 } else {
1296 int padLen = width - strLen;
1297 str.getChars(0, strLen, buffer, size);
1298 for (int i = 0; i < padLen; i++) {
1299 buffer[size + strLen + i] = padChar;
1300 }
1301 }
1302 size += width;
1303 }
1304 return this;
1305 }
1306
1307 /**
1308 * Appends an object to the builder padding on the right to a fixed length.
1309 * The <code>String.valueOf</code> of the <code>int</code> value is used.
1310 * If the object is larger than the length, the right hand side is lost.
1311 *
1312 * @param value the value to append
1313 * @param width the fixed field width, zero or negative has no effect
1314 * @param padChar the pad character to use
1315 * @return this, to enable chaining
1316 */
1317 public StrBuilder appendFixedWidthPadRight(int value, int width, char padChar) {
1318 return appendFixedWidthPadRight(String.valueOf(value), width, padChar);
1319 }
1320
1321 //-----------------------------------------------------------------------
1322 /**
1323 * Inserts the string representation of an object into this builder.
1324 * Inserting null will use the stored null text value.
1325 *
1326 * @param index the index to add at, must be valid
1327 * @param obj the object to insert
1328 * @return this, to enable chaining
1329 * @throws IndexOutOfBoundsException if the index is invalid
1330 */
1331 public StrBuilder insert(int index, Object obj) {
1332 if (obj == null) {
1333 return insert(index, nullText);
1334 }
1335 return insert(index, obj.toString());
1336 }
1337
1338 /**
1339 * Inserts the string into this builder.
1340 * Inserting null will use the stored null text value.
1341 *
1342 * @param index the index to add at, must be valid
1343 * @param str the string to insert
1344 * @return this, to enable chaining
1345 * @throws IndexOutOfBoundsException if the index is invalid
1346 */
1347 public StrBuilder insert(int index, String str) {
1348 validateIndex(index);
1349 if (str == null) {
1350 str = nullText;
1351 }
1352 int strLen = (str == null ? 0 : str.length());
1353 if (strLen > 0) {
1354 int newSize = size + strLen;
1355 ensureCapacity(newSize);
1356 System.arraycopy(buffer, index, buffer, index + strLen, size - index);
1357 size = newSize;
1358 str.getChars(0, strLen, buffer, index); // str cannot be null here
1359 }
1360 return this;
1361 }
1362
1363 /**
1364 * Inserts the character array into this builder.
1365 * Inserting null will use the stored null text value.
1366 *
1367 * @param index the index to add at, must be valid
1368 * @param chars the char array to insert
1369 * @return this, to enable chaining
1370 * @throws IndexOutOfBoundsException if the index is invalid
1371 */
1372 public StrBuilder insert(int index, char chars[]) {
1373 validateIndex(index);
1374 if (chars == null) {
1375 return insert(index, nullText);
1376 }
1377 int len = chars.length;
1378 if (len > 0) {
1379 ensureCapacity(size + len);
1380 System.arraycopy(buffer, index, buffer, index + len, size - index);
1381 System.arraycopy(chars, 0, buffer, index, len);
1382 size += len;
1383 }
1384 return this;
1385 }
1386
1387 /**
1388 * Inserts part of the character array into this builder.
1389 * Inserting null will use the stored null text value.
1390 *
1391 * @param index the index to add at, must be valid
1392 * @param chars the char array to insert
1393 * @param offset the offset into the character array to start at, must be valid
1394 * @param length the length of the character array part to copy, must be positive
1395 * @return this, to enable chaining
1396 * @throws IndexOutOfBoundsException if any index is invalid
1397 */
1398 public StrBuilder insert(int index, char chars[], int offset, int length) {
1399 validateIndex(index);
1400 if (chars == null) {
1401 return insert(index, nullText);
1402 }
1403 if (offset < 0 || offset > chars.length) {
1404 throw new StringIndexOutOfBoundsException("Invalid offset: " + offset);
1405 }
1406 if (length < 0 || offset + length > chars.length) {
1407 throw new StringIndexOutOfBoundsException("Invalid length: " + length);
1408 }
1409 if (length > 0) {
1410 ensureCapacity(size + length);
1411 System.arraycopy(buffer, index, buffer, index + length, size - index);
1412 System.arraycopy(chars, offset, buffer, index, length);
1413 size += length;
1414 }
1415 return this;
1416 }
1417
1418 /**
1419 * Inserts the value into this builder.
1420 *
1421 * @param index the index to add at, must be valid
1422 * @param value the value to insert
1423 * @return this, to enable chaining
1424 * @throws IndexOutOfBoundsException if the index is invalid
1425 */
1426 public StrBuilder insert(int index, boolean value) {
1427 validateIndex(index);
1428 if (value) {
1429 ensureCapacity(size + 4);
1430 System.arraycopy(buffer, index, buffer, index + 4, size - index);
1431 buffer[index++] = 't';
1432 buffer[index++] = 'r';
1433 buffer[index++] = 'u';
1434 buffer[index] = 'e';
1435 size += 4;
1436 } else {
1437 ensureCapacity(size + 5);
1438 System.arraycopy(buffer, index, buffer, index + 5, size - index);
1439 buffer[index++] = 'f';
1440 buffer[index++] = 'a';
1441 buffer[index++] = 'l';
1442 buffer[index++] = 's';
1443 buffer[index] = 'e';
1444 size += 5;
1445 }
1446 return this;
1447 }
1448
1449 /**
1450 * Inserts the value into this builder.
1451 *
1452 * @param index the index to add at, must be valid
1453 * @param value the value to insert
1454 * @return this, to enable chaining
1455 * @throws IndexOutOfBoundsException if the index is invalid
1456 */
1457 public StrBuilder insert(int index, char value) {
1458 validateIndex(index);
1459 ensureCapacity(size + 1);
1460 System.arraycopy(buffer, index, buffer, index + 1, size - index);
1461 buffer[index] = value;
1462 size++;
1463 return this;
1464 }
1465
1466 /**
1467 * Inserts the value into this builder.
1468 *
1469 * @param index the index to add at, must be valid
1470 * @param value the value to insert
1471 * @return this, to enable chaining
1472 * @throws IndexOutOfBoundsException if the index is invalid
1473 */
1474 public StrBuilder insert(int index, int value) {
1475 return insert(index, String.valueOf(value));
1476 }
1477
1478 /**
1479 * Inserts the value into this builder.
1480 *
1481 * @param index the index to add at, must be valid
1482 * @param value the value to insert
1483 * @return this, to enable chaining
1484 * @throws IndexOutOfBoundsException if the index is invalid
1485 */
1486 public StrBuilder insert(int index, long value) {
1487 return insert(index, String.valueOf(value));
1488 }
1489
1490 /**
1491 * Inserts the value into this builder.
1492 *
1493 * @param index the index to add at, must be valid
1494 * @param value the value to insert
1495 * @return this, to enable chaining
1496 * @throws IndexOutOfBoundsException if the index is invalid
1497 */
1498 public StrBuilder insert(int index, float value) {
1499 return insert(index, String.valueOf(value));
1500 }
1501
1502 /**
1503 * Inserts the value into this builder.
1504 *
1505 * @param index the index to add at, must be valid
1506 * @param value the value to insert
1507 * @return this, to enable chaining
1508 * @throws IndexOutOfBoundsException if the index is invalid
1509 */
1510 public StrBuilder insert(int index, double value) {
1511 return insert(index, String.valueOf(value));
1512 }
1513
1514 //-----------------------------------------------------------------------
1515 /**
1516 * Internal method to delete a range without validation.
1517 *
1518 * @param startIndex the start index, must be valid
1519 * @param endIndex the end index (exclusive), must be valid
1520 * @param len the length, must be valid
1521 * @throws IndexOutOfBoundsException if any index is invalid
1522 */
1523 private void deleteImpl(int startIndex, int endIndex, int len) {
1524 System.arraycopy(buffer, endIndex, buffer, startIndex, size - endIndex);
1525 size -= len;
1526 }
1527
1528 /**
1529 * Deletes the characters between the two specified indices.
1530 *
1531 * @param startIndex the start index, inclusive, must be valid
1532 * @param endIndex the end index, exclusive, must be valid except
1533 * that if too large it is treated as end of string
1534 * @return this, to enable chaining
1535 * @throws IndexOutOfBoundsException if the index is invalid
1536 */
1537 public StrBuilder delete(int startIndex, int endIndex) {
1538 endIndex = validateRange(startIndex, endIndex);
1539 int len = endIndex - startIndex;
1540 if (len > 0) {
1541 deleteImpl(startIndex, endIndex, len);
1542 }
1543 return this;
1544 }
1545
1546 //-----------------------------------------------------------------------
1547 /**
1548 * Deletes the character wherever it occurs in the builder.
1549 *
1550 * @param ch the character to delete
1551 * @return this, to enable chaining
1552 */
1553 public StrBuilder deleteAll(char ch) {
1554 for (int i = 0; i < size; i++) {
1555 if (buffer[i] == ch) {
1556 int start = i;
1557 while (++i < size) {
1558 if (buffer[i] != ch) {
1559 break;
1560 }
1561 }
1562 int len = i - start;
1563 deleteImpl(start, i, len);
1564 i -= len;
1565 }
1566 }
1567 return this;
1568 }
1569
1570 /**
1571 * Deletes the character wherever it occurs in the builder.
1572 *
1573 * @param ch the character to delete
1574 * @return this, to enable chaining
1575 */
1576 public StrBuilder deleteFirst(char ch) {
1577 for (int i = 0; i < size; i++) {
1578 if (buffer[i] == ch) {
1579 deleteImpl(i, i + 1, 1);
1580 break;
1581 }
1582 }
1583 return this;
1584 }
1585
1586 //-----------------------------------------------------------------------
1587 /**
1588 * Deletes the string wherever it occurs in the builder.
1589 *
1590 * @param str the string to delete, null causes no action
1591 * @return this, to enable chaining
1592 */
1593 public StrBuilder deleteAll(String str) {
1594 int len = (str == null ? 0 : str.length());
1595 if (len > 0) {
1596 int index = indexOf(str, 0);
1597 while (index >= 0) {
1598 deleteImpl(index, index + len, len);
1599 index = indexOf(str, index);
1600 }
1601 }
1602 return this;
1603 }
1604
1605 /**
1606 * Deletes the string wherever it occurs in the builder.
1607 *
1608 * @param str the string to delete, null causes no action
1609 * @return this, to enable chaining
1610 */
1611 public StrBuilder deleteFirst(String str) {
1612 int len = (str == null ? 0 : str.length());
1613 if (len > 0) {
1614 int index = indexOf(str, 0);
1615 if (index >= 0) {
1616 deleteImpl(index, index + len, len);
1617 }
1618 }
1619 return this;
1620 }
1621
1622 //-----------------------------------------------------------------------
1623 /**
1624 * Deletes all parts of the builder that the matcher matches.
1625 * <p>
1626 * Matchers can be used to perform advanced deletion behaviour.
1627 * For example you could write a matcher to delete all occurances
1628 * where the character 'a' is followed by a number.
1629 *
1630 * @param matcher the matcher to use to find the deletion, null causes no action
1631 * @return this, to enable chaining
1632 */
1633 public StrBuilder deleteAll(StrMatcher matcher) {
1634 return replace(matcher, null, 0, size, -1);
1635 }
1636
1637 /**
1638 * Deletes the first match within the builder using the specified matcher.
1639 * <p>
1640 * Matchers can be used to perform advanced deletion behaviour.
1641 * For example you could write a matcher to delete
1642 * where the character 'a' is followed by a number.
1643 *
1644 * @param matcher the matcher to use to find the deletion, null causes no action
1645 * @return this, to enable chaining
1646 */
1647 public StrBuilder deleteFirst(StrMatcher matcher) {
1648 return replace(matcher, null, 0, size, 1);
1649 }
1650
1651 //-----------------------------------------------------------------------
1652 /**
1653 * Internal method to delete a range without validation.
1654 *
1655 * @param startIndex the start index, must be valid
1656 * @param endIndex the end index (exclusive), must be valid
1657 * @param removeLen the length to remove (endIndex - startIndex), must be valid
1658 * @param insertStr the string to replace with, null means delete range
1659 * @param insertLen the length of the insert string, must be valid
1660 * @throws IndexOutOfBoundsException if any index is invalid
1661 */
1662 private void replaceImpl(int startIndex, int endIndex, int removeLen, String insertStr, int insertLen) {
1663 int newSize = size - removeLen + insertLen;
1664 if (insertLen != removeLen) {
1665 ensureCapacity(newSize);
1666 System.arraycopy(buffer, endIndex, buffer, startIndex + insertLen, size - endIndex);
1667 size = newSize;
1668 }
1669 if (insertLen > 0) {
1670 insertStr.getChars(0, insertLen, buffer, startIndex);
1671 }
1672 }
1673
1674 /**
1675 * Replaces a portion of the string builder with another string.
1676 * The length of the inserted string does not have to match the removed length.
1677 *
1678 * @param startIndex the start index, inclusive, must be valid
1679 * @param endIndex the end index, exclusive, must be valid except
1680 * that if too large it is treated as end of string
1681 * @param replaceStr the string to replace with, null means delete range
1682 * @return this, to enable chaining
1683 * @throws IndexOutOfBoundsException if the index is invalid
1684 */
1685 public StrBuilder replace(int startIndex, int endIndex, String replaceStr) {
1686 endIndex = validateRange(startIndex, endIndex);
1687 int insertLen = (replaceStr == null ? 0 : replaceStr.length());
1688 replaceImpl(startIndex, endIndex, endIndex - startIndex, replaceStr, insertLen);
1689 return this;
1690 }
1691
1692 //-----------------------------------------------------------------------
1693 /**
1694 * Replaces the search character with the replace character
1695 * throughout the builder.
1696 *
1697 * @param search the search character
1698 * @param replace the replace character
1699 * @return this, to enable chaining
1700 */
1701 public StrBuilder replaceAll(char search, char replace) {
1702 if (search != replace) {
1703 for (int i = 0; i < size; i++) {
1704 if (buffer[i] == search) {
1705 buffer[i] = replace;
1706 }
1707 }
1708 }
1709 return this;
1710 }
1711
1712 /**
1713 * Replaces the first instance of the search character with the
1714 * replace character in the builder.
1715 *
1716 * @param search the search character
1717 * @param replace the replace character
1718 * @return this, to enable chaining
1719 */
1720 public StrBuilder replaceFirst(char search, char replace) {
1721 if (search != replace) {
1722 for (int i = 0; i < size; i++) {
1723 if (buffer[i] == search) {
1724 buffer[i] = replace;
1725 break;
1726 }
1727 }
1728 }
1729 return this;
1730 }
1731
1732 //-----------------------------------------------------------------------
1733 /**
1734 * Replaces the search string with the replace string throughout the builder.
1735 *
1736 * @param searchStr the search string, null causes no action to occur
1737 * @param replaceStr the replace string, null is equivalent to an empty string
1738 * @return this, to enable chaining
1739 */
1740 public StrBuilder replaceAll(String searchStr, String replaceStr) {
1741 int searchLen = (searchStr == null ? 0 : searchStr.length());
1742 if (searchLen > 0) {
1743 int replaceLen = (replaceStr == null ? 0 : replaceStr.length());
1744 int index = indexOf(searchStr, 0);
1745 while (index >= 0) {
1746 replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen);
1747 index = indexOf(searchStr, index + replaceLen);
1748 }
1749 }
1750 return this;
1751 }
1752
1753 /**
1754 * Replaces the first instance of the search string with the replace string.
1755 *
1756 * @param searchStr the search string, null causes no action to occur
1757 * @param replaceStr the replace string, null is equivalent to an empty string
1758 * @return this, to enable chaining
1759 */
1760 public StrBuilder replaceFirst(String searchStr, String replaceStr) {
1761 int searchLen = (searchStr == null ? 0 : searchStr.length());
1762 if (searchLen > 0) {
1763 int index = indexOf(searchStr, 0);
1764 if (index >= 0) {
1765 int replaceLen = (replaceStr == null ? 0 : replaceStr.length());
1766 replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen);
1767 }
1768 }
1769 return this;
1770 }
1771
1772 //-----------------------------------------------------------------------
1773 /**
1774 * Replaces all matches within the builder with the replace string.
1775 * <p>
1776 * Matchers can be used to perform advanced replace behaviour.
1777 * For example you could write a matcher to replace all occurances
1778 * where the character 'a' is followed by a number.
1779 *
1780 * @param matcher the matcher to use to find the deletion, null causes no action
1781 * @param replaceStr the replace string, null is equivalent to an empty string
1782 * @return this, to enable chaining
1783 */
1784 public StrBuilder replaceAll(StrMatcher matcher, String replaceStr) {
1785 return replace(matcher, replaceStr, 0, size, -1);
1786 }
1787
1788 /**
1789 * Replaces the first match within the builder with the replace string.
1790 * <p>
1791 * Matchers can be used to perform advanced replace behaviour.
1792 * For example you could write a matcher to replace
1793 * where the character 'a' is followed by a number.
1794 *
1795 * @param matcher the matcher to use to find the deletion, null causes no action
1796 * @param replaceStr the replace string, null is equivalent to an empty string
1797 * @return this, to enable chaining
1798 */
1799 public StrBuilder replaceFirst(StrMatcher matcher, String replaceStr) {
1800 return replace(matcher, replaceStr, 0, size, 1);
1801 }
1802
1803 // -----------------------------------------------------------------------
1804 /**
1805 * Advanced search and replaces within the builder using a matcher.
1806 * <p>
1807 * Matchers can be used to perform advanced behaviour.
1808 * For example you could write a matcher to delete all occurances
1809 * where the character 'a' is followed by a number.
1810 *
1811 * @param matcher the matcher to use to find the deletion, null causes no action
1812 * @param replaceStr the string to replace the match with, null is a delete
1813 * @param startIndex the start index, inclusive, must be valid
1814 * @param endIndex the end index, exclusive, must be valid except
1815 * that if too large it is treated as end of string
1816 * @param replaceCount the number of times to replace, -1 for replace all
1817 * @return this, to enable chaining
1818 * @throws IndexOutOfBoundsException if start index is invalid
1819 */
1820 public StrBuilder replace(
1821 StrMatcher matcher, String replaceStr,
1822 int startIndex, int endIndex, int replaceCount) {
1823 endIndex = validateRange(startIndex, endIndex);
1824 return replaceImpl(matcher, replaceStr, startIndex, endIndex, replaceCount);
1825 }
1826
1827 /**
1828 * Replaces within the builder using a matcher.
1829 * <p>
1830 * Matchers can be used to perform advanced behaviour.
1831 * For example you could write a matcher to delete all occurances
1832 * where the character 'a' is followed by a number.
1833 *
1834 * @param matcher the matcher to use to find the deletion, null causes no action
1835 * @param replaceStr the string to replace the match with, null is a delete
1836 * @param from the start index, must be valid
1837 * @param to the end index (exclusive), must be valid
1838 * @param replaceCount the number of times to replace, -1 for replace all
1839 * @return this, to enable chaining
1840 * @throws IndexOutOfBoundsException if any index is invalid
1841 */
1842 private StrBuilder replaceImpl(
1843 StrMatcher matcher, String replaceStr,
1844 int from, int to, int replaceCount) {
1845 if (matcher == null || size == 0) {
1846 return this;
1847 }
1848 int replaceLen = (replaceStr == null ? 0 : replaceStr.length());
1849 char[] buf = buffer;
1850 for (int i = from; i < to && replaceCount != 0; i++) {
1851 int removeLen = matcher.isMatch(buf, i, from, to);
1852 if (removeLen > 0) {
1853 replaceImpl(i, i + removeLen, removeLen, replaceStr, replaceLen);
1854 to = to - removeLen + replaceLen;
1855 i = i + replaceLen - 1;
1856 if (replaceCount > 0) {
1857 replaceCount--;
1858 }
1859 }
1860 }
1861 return this;
1862 }
1863
1864 //-----------------------------------------------------------------------
1865 /**
1866 * Reverses the string builder placing each character in the opposite index.
1867 *
1868 * @return this, to enable chaining
1869 */
1870 public StrBuilder reverse() {
1871 if (size == 0) {
1872 return this;
1873 }
1874
1875 int half = size / 2;
1876 char[] buf = buffer;
1877 for (int leftIdx = 0, rightIdx = size - 1; leftIdx < half; leftIdx++,rightIdx--) {
1878 char swap = buf[leftIdx];
1879 buf[leftIdx] = buf[rightIdx];
1880 buf[rightIdx] = swap;
1881 }
1882 return this;
1883 }
1884
1885 //-----------------------------------------------------------------------
1886 /**
1887 * Trims the builder by removing characters less than or equal to a space
1888 * from the beginning and end.
1889 *
1890 * @return this, to enable chaining
1891 */
1892 public StrBuilder trim() {
1893 if (size == 0) {
1894 return this;
1895 }
1896 int len = size;
1897 char[] buf = buffer;
1898 int pos = 0;
1899 while (pos < len && buf[pos] <= ' ') {
1900 pos++;
1901 }
1902 while (pos < len && buf[len - 1] <= ' ') {
1903 len--;
1904 }
1905 if (len < size) {
1906 delete(len, size);
1907 }
1908 if (pos > 0) {
1909 delete(0, pos);
1910 }
1911 return this;
1912 }
1913
1914 //-----------------------------------------------------------------------
1915 /**
1916 * Checks whether this builder starts with the specified string.
1917 * <p>
1918 * Note that this method handles null input quietly, unlike String.
1919 *
1920 * @param str the string to search for, null returns false
1921 * @return true if the builder starts with the string
1922 */
1923 public boolean startsWith(String str) {
1924 if (str == null) {
1925 return false;
1926 }
1927 int len = str.length();
1928 if (len == 0) {
1929 return true;
1930 }
1931 if (len > size) {
1932 return false;
1933 }
1934 for (int i = 0; i < len; i++) {
1935 if (buffer[i] != str.charAt(i)) {
1936 return false;
1937 }
1938 }
1939 return true;
1940 }
1941
1942 /**
1943 * Checks whether this builder ends with the specified string.
1944 * <p>
1945 * Note that this method handles null input quietly, unlike String.
1946 *
1947 * @param str the string to search for, null returns false
1948 * @return true if the builder ends with the string
1949 */
1950 public boolean endsWith(String str) {
1951 if (str == null) {
1952 return false;
1953 }
1954 int len = str.length();
1955 if (len == 0) {
1956 return true;
1957 }
1958 if (len > size) {
1959 return false;
1960 }
1961 int pos = size - len;
1962 for (int i = 0; i < len; i++,pos++) {
1963 if (buffer[pos] != str.charAt(i)) {
1964 return false;
1965 }
1966 }
1967 return true;
1968 }
1969
1970 //-----------------------------------------------------------------------
1971 /**
1972 * Extracts a portion of this string builder as a string.
1973 *
1974 * @param start the start index, inclusive, must be valid
1975 * @return the new string
1976 * @throws IndexOutOfBoundsException if the index is invalid
1977 */
1978 public String substring(int start) {
1979 return substring(start, size);
1980 }
1981
1982 /**
1983 * Extracts a portion of this string builder as a string.
1984 * <p>
1985 * Note: This method treats an endIndex greater than the length of the
1986 * builder as equal to the length of the builder, and continues
1987 * without error, unlike StringBuffer or String.
1988 *
1989 * @param startIndex the start index, inclusive, must be valid
1990 * @param endIndex the end index, exclusive, must be valid except
1991 * that if too large it is treated as end of string
1992 * @return the new string
1993 * @throws IndexOutOfBoundsException if the index is invalid
1994 */
1995 public String substring(int startIndex, int endIndex) {
1996 endIndex = validateRange(startIndex, endIndex);
1997 return new String(buffer, startIndex, endIndex - startIndex);
1998 }
1999
2000 /**
2001 * Extracts the leftmost characters from the string builder without
2002 * throwing an exception.
2003 * <p>
2004 * This method extracts the left <code>length</code> characters from
2005 * the builder. If this many characters are not available, the whole
2006 * builder is returned. Thus the returned string may be shorter than the
2007 * length requested.
2008 *
2009 * @param length the number of characters to extract, negative returns empty string
2010 * @return the new string
2011 */
2012 public String leftString(int length) {
2013 if (length <= 0) {
2014 return "";
2015 } else if (length >= size) {
2016 return new String(buffer, 0, size);
2017 } else {
2018 return new String(buffer, 0, length);
2019 }
2020 }
2021
2022 /**
2023 * Extracts the rightmost characters from the string builder without
2024 * throwing an exception.
2025 * <p>
2026 * This method extracts the right <code>length</code> characters from
2027 * the builder. If this many characters are not available, the whole
2028 * builder is returned. Thus the returned string may be shorter than the
2029 * length requested.
2030 *
2031 * @param length the number of characters to extract, negative returns empty string
2032 * @return the new string
2033 */
2034 public String rightString(int length) {
2035 if (length <= 0) {
2036 return "";
2037 } else if (length >= size) {
2038 return new String(buffer, 0, size);
2039 } else {
2040 return new String(buffer, size - length, length);
2041 }
2042 }
2043
2044 /**
2045 * Extracts some characters from the middle of the string builder without
2046 * throwing an exception.
2047 * <p>
2048 * This method extracts <code>length</code> characters from the builder
2049 * at the specified index.
2050 * If the index is negative it is treated as zero.
2051 * If the index is greater than the builder size, it is treated as the builder size.
2052 * If the length is negative, the empty string is returned.
2053 * If insufficient characters are available in the builder, as much as possible is returned.
2054 * Thus the returned string may be shorter than the length requested.
2055 *
2056 * @param index the index to start at, negative means zero
2057 * @param length the number of characters to extract, negative returns empty string
2058 * @return the new string
2059 */
2060 public String midString(int index, int length) {
2061 if (index < 0) {
2062 index = 0;
2063 }
2064 if (length <= 0 || index >= size) {
2065 return "";
2066 }
2067 if (size <= index + length) {
2068 return new String(buffer, index, size - index);
2069 } else {
2070 return new String(buffer, index, length);
2071 }
2072 }
2073
2074 //-----------------------------------------------------------------------
2075 /**
2076 * Checks if the string builder contains the specified char.
2077 *
2078 * @param ch the character to find
2079 * @return true if the builder contains the character
2080 */
2081 public boolean contains(char ch) {
2082 char[] thisBuf = buffer;
2083 for (int i = 0; i < this.size; i++) {
2084 if (thisBuf[i] == ch) {
2085 return true;
2086 }
2087 }
2088 return false;
2089 }
2090
2091 /**
2092 * Checks if the string builder contains the specified string.
2093 *
2094 * @param str the string to find
2095 * @return true if the builder contains the string
2096 */
2097 public boolean contains(String str) {
2098 return indexOf(str, 0) >= 0;
2099 }
2100
2101 /**
2102 * Checks if the string builder contains a string matched using the
2103 * specified matcher.
2104 * <p>
2105 * Matchers can be used to perform advanced searching behaviour.
2106 * For example you could write a matcher to search for the character
2107 * 'a' followed by a number.
2108 *
2109 * @param matcher the matcher to use, null returns -1
2110 * @return true if the matcher finds a match in the builder
2111 */
2112 public boolean contains(StrMatcher matcher) {
2113 return indexOf(matcher, 0) >= 0;
2114 }
2115
2116 //-----------------------------------------------------------------------
2117 /**
2118 * Searches the string builder to find the first reference to the specified char.
2119 *
2120 * @param ch the character to find
2121 * @return the first index of the character, or -1 if not found
2122 */
2123 public int indexOf(char ch) {
2124 return indexOf(ch, 0);
2125 }
2126
2127 /**
2128 * Searches the string builder to find the first reference to the specified char.
2129 *
2130 * @param ch the character to find
2131 * @param startIndex the index to start at, invalid index rounded to edge
2132 * @return the first index of the character, or -1 if not found
2133 */
2134 public int indexOf(char ch, int startIndex) {
2135 startIndex = (startIndex < 0 ? 0 : startIndex);
2136 if (startIndex >= size) {
2137 return -1;
2138 }
2139 char[] thisBuf = buffer;
2140 for (int i = startIndex; i < size; i++) {
2141 if (thisBuf[i] == ch) {
2142 return i;
2143 }
2144 }
2145 return -1;
2146 }
2147
2148 /**
2149 * Searches the string builder to find the first reference to the specified string.
2150 * <p>
2151 * Note that a null input string will return -1, whereas the JDK throws an exception.
2152 *
2153 * @param str the string to find, null returns -1
2154 * @return the first index of the string, or -1 if not found
2155 */
2156 public int indexOf(String str) {
2157 return indexOf(str, 0);
2158 }
2159
2160 /**
2161 * Searches the string builder to find the first reference to the specified
2162 * string starting searching from the given index.
2163 * <p>
2164 * Note that a null input string will return -1, whereas the JDK throws an exception.
2165 *
2166 * @param str the string to find, null returns -1
2167 * @param startIndex the index to start at, invalid index rounded to edge
2168 * @return the first index of the string, or -1 if not found
2169 */
2170 public int indexOf(String str, int startIndex) {
2171 startIndex = (startIndex < 0 ? 0 : startIndex);
2172 if (str == null || startIndex >= size) {
2173 return -1;
2174 }
2175 int strLen = str.length();
2176 if (strLen == 1) {
2177 return indexOf(str.charAt(0), startIndex);
2178 }
2179 if (strLen == 0) {
2180 return startIndex;
2181 }
2182 if (strLen > size) {
2183 return -1;
2184 }
2185 char[] thisBuf = buffer;
2186 int len = size - strLen + 1;
2187 outer:
2188 for (int i = startIndex; i < len; i++) {
2189 for (int j = 0; j < strLen; j++) {
2190 if (str.charAt(j) != thisBuf[i + j]) {
2191 continue outer;
2192 }
2193 }
2194 return i;
2195 }
2196 return -1;
2197 }
2198
2199 /**
2200 * Searches the string builder using the matcher to find the first match.
2201 * <p>
2202 * Matchers can be used to perform advanced searching behaviour.
2203 * For example you could write a matcher to find the character 'a'
2204 * followed by a number.
2205 *
2206 * @param matcher the matcher to use, null returns -1
2207 * @return the first index matched, or -1 if not found
2208 */
2209 public int indexOf(StrMatcher matcher) {
2210 return indexOf(matcher, 0);
2211 }
2212
2213 /**
2214 * Searches the string builder using the matcher to find the first
2215 * match searching from the given index.
2216 * <p>
2217 * Matchers can be used to perform advanced searching behaviour.
2218 * For example you could write a matcher to find the character 'a'
2219 * followed by a number.
2220 *
2221 * @param matcher the matcher to use, null returns -1
2222 * @param startIndex the index to start at, invalid index rounded to edge
2223 * @return the first index matched, or -1 if not found
2224 */
2225 public int indexOf(StrMatcher matcher, int startIndex) {
2226 startIndex = (startIndex < 0 ? 0 : startIndex);
2227 if (matcher == null || startIndex >= size) {
2228 return -1;
2229 }
2230 int len = size;
2231 char[] buf = buffer;
2232 for (int i = startIndex; i < len; i++) {
2233 if (matcher.isMatch(buf, i, startIndex, len) > 0) {
2234 return i;
2235 }
2236 }
2237 return -1;
2238 }
2239
2240 //-----------------------------------------------------------------------
2241 /**
2242 * Searches the string builder to find the last reference to the specified char.
2243 *
2244 * @param ch the character to find
2245 * @return the last index of the character, or -1 if not found
2246 */
2247 public int lastIndexOf(char ch) {
2248 return lastIndexOf(ch, size - 1);
2249 }
2250
2251 /**
2252 * Searches the string builder to find the last reference to the specified char.
2253 *
2254 * @param ch the character to find
2255 * @param startIndex the index to start at, invalid index rounded to edge
2256 * @return the last index of the character, or -1 if not found
2257 */
2258 public int lastIndexOf(char ch, int startIndex) {
2259 startIndex = (startIndex >= size ? size - 1 : startIndex);
2260 if (startIndex < 0) {
2261 return -1;
2262 }
2263 for (int i = startIndex; i >= 0; i--) {
2264 if (buffer[i] == ch) {
2265 return i;
2266 }
2267 }
2268 return -1;
2269 }
2270
2271 /**
2272 * Searches the string builder to find the last reference to the specified string.
2273 * <p>
2274 * Note that a null input string will return -1, whereas the JDK throws an exception.
2275 *
2276 * @param str the string to find, null returns -1
2277 * @return the last index of the string, or -1 if not found
2278 */
2279 public int lastIndexOf(String str) {
2280 return lastIndexOf(str, size - 1);
2281 }
2282
2283 /**
2284 * Searches the string builder to find the last reference to the specified
2285 * string starting searching from the given index.
2286 * <p>
2287 * Note that a null input string will return -1, whereas the JDK throws an exception.
2288 *
2289 * @param str the string to find, null returns -1
2290 * @param startIndex the index to start at, invalid index rounded to edge
2291 * @return the last index of the string, or -1 if not found
2292 */
2293 public int lastIndexOf(String str, int startIndex) {
2294 startIndex = (startIndex >= size ? size - 1 : startIndex);
2295 if (str == null || startIndex < 0) {
2296 return -1;
2297 }
2298 int strLen = str.length();
2299 if (strLen > 0 && strLen <= size) {
2300 if (strLen == 1) {
2301 return lastIndexOf(str.charAt(0), startIndex);
2302 }
2303
2304 outer:
2305 for (int i = startIndex - strLen + 1; i >= 0; i--) {
2306 for (int j = 0; j < strLen; j++) {
2307 if (str.charAt(j) != buffer[i + j]) {
2308 continue outer;
2309 }
2310 }
2311 return i;
2312 }
2313
2314 } else if (strLen == 0) {
2315 return startIndex;
2316 }
2317 return -1;
2318 }
2319
2320 /**
2321 * Searches the string builder using the matcher to find the last match.
2322 * <p>
2323 * Matchers can be used to perform advanced searching behaviour.
2324 * For example you could write a matcher to find the character 'a'
2325 * followed by a number.
2326 *
2327 * @param matcher the matcher to use, null returns -1
2328 * @return the last index matched, or -1 if not found
2329 */
2330 public int lastIndexOf(StrMatcher matcher) {
2331 return lastIndexOf(matcher, size);
2332 }
2333
2334 /**
2335 * Searches the string builder using the matcher to find the last
2336 * match searching from the given index.
2337 * <p>
2338 * Matchers can be used to perform advanced searching behaviour.
2339 * For example you could write a matcher to find the character 'a'
2340 * followed by a number.
2341 *
2342 * @param matcher the matcher to use, null returns -1
2343 * @param startIndex the index to start at, invalid index rounded to edge
2344 * @return the last index matched, or -1 if not found
2345 */
2346 public int lastIndexOf(StrMatcher matcher, int startIndex) {
2347 startIndex = (startIndex >= size ? size - 1 : startIndex);
2348 if (matcher == null || startIndex < 0) {
2349 return -1;
2350 }
2351 char[] buf = buffer;
2352 int endIndex = startIndex + 1;
2353 for (int i = startIndex; i >= 0; i--) {
2354 if (matcher.isMatch(buf, i, 0, endIndex) > 0) {
2355 return i;
2356 }
2357 }
2358 return -1;
2359 }
2360
2361 //-----------------------------------------------------------------------
2362 /**
2363 * Creates a tokenizer that can tokenize the contents of this builder.
2364 * <p>
2365 * This method allows the contents of this builder to be tokenized.
2366 * The tokenizer will be setup by default to tokenize on space, tab,
2367 * newline and formfeed (as per StringTokenizer). These values can be
2368 * changed on the tokenizer class, before retrieving the tokens.
2369 * <p>
2370 * The returned tokenizer is linked to this builder. You may intermix
2371 * calls to the buider and tokenizer within certain limits, however
2372 * there is no synchronization. Once the tokenizer has been used once,
2373 * it must be {@link StrTokenizer#reset() reset} to pickup the latest
2374 * changes in the builder. For example:
2375 * <pre>
2376 * StrBuilder b = new StrBuilder();
2377 * b.append("a b ");
2378 * StrTokenizer t = b.asTokenizer();
2379 * String[] tokens1 = t.getTokenArray(); // returns a,b
2380 * b.append("c d ");
2381 * String[] tokens2 = t.getTokenArray(); // returns a,b (c and d ignored)
2382 * t.reset(); // reset causes builder changes to be picked up
2383 * String[] tokens3 = t.getTokenArray(); // returns a,b,c,d
2384 * </pre>
2385 * In addition to simply intermixing appends and tokenization, you can also
2386 * call the set methods on the tokenizer to alter how it tokenizes. Just
2387 * remember to call reset when you want to pickup builder changes.
2388 * <p>
2389 * Calling {@link StrTokenizer#reset(String)} or {@link StrTokenizer#reset(char[])}
2390 * with a non-null value will break the link with the builder.
2391 *
2392 * @return a tokenizer that is linked to this builder
2393 */
2394 public StrTokenizer asTokenizer() {
2395 return new StrBuilderTokenizer();
2396 }
2397
2398 //-----------------------------------------------------------------------
2399 /**
2400 * Gets the contents of this builder as a Reader.
2401 * <p>
2402 * This method allows the contents of the builder to be read
2403 * using any standard method that expects a Reader.
2404 * <p>
2405 * To use, simply create a <code>StrBuilder</code>, populate it with
2406 * data, call <code>asReader</code>, and then read away.
2407 * <p>
2408 * The internal character array is shared between the builder and the reader.
2409 * This allows you to append to the builder after creating the reader,
2410 * and the changes will be picked up.
2411 * Note however, that no synchronization occurs, so you must perform
2412 * all operations with the builder and the reader in one thread.
2413 * <p>
2414 * The returned reader supports marking, and ignores the flush method.
2415 *
2416 * @return a reader that reads from this builder
2417 */
2418 public Reader asReader() {
2419 return new StrBuilderReader();
2420 }
2421
2422 //-----------------------------------------------------------------------
2423 /**
2424 * Gets this builder as a Writer that can be written to.
2425 * <p>
2426 * This method allows you to populate the contents of the builder
2427 * using any standard method that takes a Writer.
2428 * <p>
2429 * To use, simply create a <code>StrBuilder</code>,
2430 * call <code>asWriter</code>, and populate away. The data is available
2431 * at any time using the methods of the <code>StrBuilder</code>.
2432 * <p>
2433 * The internal character array is shared between the builder and the writer.
2434 * This allows you to intermix calls that append to the builder and
2435 * write using the writer and the changes will be occur correctly.
2436 * Note however, that no synchronization occurs, so you must perform
2437 * all operations with the builder and the writer in one thread.
2438 * <p>
2439 * The returned writer ignores the close and flush methods.
2440 *
2441 * @return a writer that populates this builder
2442 */
2443 public Writer asWriter() {
2444 return new StrBuilderWriter();
2445 }
2446
2447 //-----------------------------------------------------------------------
2448// /**
2449// * Gets a String version of the string builder by calling the internal
2450// * constructor of String by reflection.
2451// * <p>
2452// * WARNING: You must not use the StrBuilder after calling this method
2453// * as the buffer is now shared with the String object. To ensure this,
2454// * the internal character array is set to null, so you will get
2455// * NullPointerExceptions on all method calls.
2456// *
2457// * @return the builder as a String
2458// */
2459// public String toSharedString() {
2460// try {
2461// Constructor con = String.class.getDeclaredConstructor(
2462// new Class[] {int.class, int.class, char[].class});
2463// con.setAccessible(true);
2464// char[] buffer = buf;
2465// buf = null;
2466// size = -1;
2467// nullText = null;
2468// return (String) con.newInstance(
2469// new Object[] {new Integer(0), new Integer(size), buffer});
2470//
2471// } catch (Exception ex) {
2472// ex.printStackTrace();
2473// throw new UnsupportedOperationException("StrBuilder.toSharedString is unsupported: " + ex.getMessage());
2474// }
2475// }
2476
2477 //-----------------------------------------------------------------------
2478 /**
2479 * Checks the contents of this builder against another to see if they
2480 * contain the same character content ignoring case.
2481 *
2482 * @param other the object to check, null returns false
2483 * @return true if the builders contain the same characters in the same order
2484 */
2485 public boolean equalsIgnoreCase(StrBuilder other) {
2486 if (this == other) {
2487 return true;
2488 }
2489 if (this.size != other.size) {
2490 return false;
2491 }
2492 char thisBuf[] = this.buffer;
2493 char otherBuf[] = other.buffer;
2494 for (int i = size - 1; i >= 0; i--) {
2495 char c1 = thisBuf[i];
2496 char c2 = otherBuf[i];
2497 if (c1 != c2 && Character.toUpperCase(c1) != Character.toUpperCase(c2)) {
2498 return false;
2499 }
2500 }
2501 return true;
2502 }
2503
2504 /**
2505 * Checks the contents of this builder against another to see if they
2506 * contain the same character content.
2507 *
2508 * @param other the object to check, null returns false
2509 * @return true if the builders contain the same characters in the same order
2510 */
2511 public boolean equals(StrBuilder other) {
2512 if (this == other) {
2513 return true;
2514 }
2515 if (this.size != other.size) {
2516 return false;
2517 }
2518 char thisBuf[] = this.buffer;
2519 char otherBuf[] = other.buffer;
2520 for (int i = size - 1; i >= 0; i--) {
2521 if (thisBuf[i] != otherBuf[i]) {
2522 return false;
2523 }
2524 }
2525 return true;
2526 }
2527
2528 /**
2529 * Checks the contents of this builder against another to see if they
2530 * contain the same character content.
2531 *
2532 * @param obj the object to check, null returns false
2533 * @return true if the builders contain the same characters in the same order
2534 */
2535 public boolean equals(Object obj) {
2536 if (obj instanceof StrBuilder) {
2537 return equals((StrBuilder) obj);
2538 }
2539 return false;
2540 }
2541
2542 /**
2543 * Gets a suitable hash code for this builder.
2544 *
2545 * @return a hash code
2546 */
2547 public int hashCode() {
2548 char buf[] = buffer;
2549 int hash = 0;
2550 for (int i = size - 1; i >= 0; i--) {
2551 hash = 31 * hash + buf[i];
2552 }
2553 return hash;
2554 }
2555
2556 //-----------------------------------------------------------------------
2557 /**
2558 * Gets a String version of the string builder, creating a new instance
2559 * each time the method is called.
2560 * <p>
2561 * Note that unlike StringBuffer, the string version returned is
2562 * independent of the string builder.
2563 *
2564 * @return the builder as a String
2565 */
2566 public String toString() {
2567 return new String(buffer, 0, size);
2568 }
2569
2570 /**
2571 * Gets a StringBuffer version of the string builder, creating a
2572 * new instance each time the method is called.
2573 *
2574 * @return the builder as a StringBuffer
2575 */
2576 public StringBuffer toStringBuffer() {
2577 return new StringBuffer(size).append(buffer, 0, size);
2578 }
2579
2580 /**
2581 * Clone this object.
2582 *
2583 * @return a clone of this object
2584 * @throws CloneNotSupportedException if clone is not supported
2585 * @since 2.6
2586 */
2587 public Object clone() throws CloneNotSupportedException {
2588 StrBuilder clone = (StrBuilder)super.clone();
2589 clone.buffer = new char[buffer.length];
2590 System.arraycopy(buffer, 0, clone.buffer, 0, buffer.length);
2591 return clone;
2592 }
2593
2594 //-----------------------------------------------------------------------
2595 /**
2596 * Validates parameters defining a range of the builder.
2597 *
2598 * @param startIndex the start index, inclusive, must be valid
2599 * @param endIndex the end index, exclusive, must be valid except
2600 * that if too large it is treated as end of string
2601 * @return the new string
2602 * @throws IndexOutOfBoundsException if the index is invalid
2603 */
2604 protected int validateRange(int startIndex, int endIndex) {
2605 if (startIndex < 0) {
2606 throw new StringIndexOutOfBoundsException(startIndex);
2607 }
2608 if (endIndex > size) {
2609 endIndex = size;
2610 }
2611 if (startIndex > endIndex) {
2612 throw new StringIndexOutOfBoundsException("end < start");
2613 }
2614 return endIndex;
2615 }
2616
2617 /**
2618 * Validates parameters defining a single index in the builder.
2619 *
2620 * @param index the index, must be valid
2621 * @throws IndexOutOfBoundsException if the index is invalid
2622 */
2623 protected void validateIndex(int index) {
2624 if (index < 0 || index > size) {
2625 throw new StringIndexOutOfBoundsException(index);
2626 }
2627 }
2628
2629 //-----------------------------------------------------------------------
2630 /**
2631 * Inner class to allow StrBuilder to operate as a tokenizer.
2632 */
2633 class StrBuilderTokenizer extends StrTokenizer {
2634
2635 /**
2636 * Default constructor.
2637 */
2638 StrBuilderTokenizer() {
2639 super();
2640 }
2641
2642 /** {@inheritDoc} */
2643 protected List tokenize(char[] chars, int offset, int count) {
2644 if (chars == null) {
2645 return super.tokenize(StrBuilder.this.buffer, 0, StrBuilder.this.size());
2646 } else {
2647 return super.tokenize(chars, offset, count);
2648 }
2649 }
2650
2651 /** {@inheritDoc} */
2652 public String getContent() {
2653 String str = super.getContent();
2654 if (str == null) {
2655 return StrBuilder.this.toString();
2656 } else {
2657 return str;
2658 }
2659 }
2660 }
2661
2662 //-----------------------------------------------------------------------
2663 /**
2664 * Inner class to allow StrBuilder to operate as a writer.
2665 */
2666 class StrBuilderReader extends Reader {
2667 /** The current stream position. */
2668 private int pos;
2669 /** The last mark position. */
2670 private int mark;
2671
2672 /**
2673 * Default constructor.
2674 */
2675 StrBuilderReader() {
2676 super();
2677 }
2678
2679 /** {@inheritDoc} */
2680 public void close() {
2681 // do nothing
2682 }
2683
2684 /** {@inheritDoc} */
2685 public int read() {
2686 if (ready() == false) {
2687 return -1;
2688 }
2689 return StrBuilder.this.charAt(pos++);
2690 }
2691
2692 /** {@inheritDoc} */
2693 public int read(char b[], int off, int len) {
2694 if (off < 0 || len < 0 || off > b.length ||
2695 (off + len) > b.length || (off + len) < 0) {
2696 throw new IndexOutOfBoundsException();
2697 }
2698 if (len == 0) {
2699 return 0;
2700 }
2701 if (pos >= StrBuilder.this.size()) {
2702 return -1;
2703 }
2704 if (pos + len > size()) {
2705 len = StrBuilder.this.size() - pos;
2706 }
2707 StrBuilder.this.getChars(pos, pos + len, b, off);
2708 pos += len;
2709 return len;
2710 }
2711
2712 /** {@inheritDoc} */
2713 public long skip(long n) {
2714 if (pos + n > StrBuilder.this.size()) {
2715 n = StrBuilder.this.size() - pos;
2716 }
2717 if (n < 0) {
2718 return 0;
2719 }
2720 pos += n;
2721 return n;
2722 }
2723
2724 /** {@inheritDoc} */
2725 public boolean ready() {
2726 return pos < StrBuilder.this.size();
2727 }
2728
2729 /** {@inheritDoc} */
2730 public boolean markSupported() {
2731 return true;
2732 }
2733
2734 /** {@inheritDoc} */
2735 public void mark(int readAheadLimit) {
2736 mark = pos;
2737 }
2738
2739 /** {@inheritDoc} */
2740 public void reset() {
2741 pos = mark;
2742 }
2743 }
2744
2745 //-----------------------------------------------------------------------
2746 /**
2747 * Inner class to allow StrBuilder to operate as a writer.
2748 */
2749 class StrBuilderWriter extends Writer {
2750
2751 /**
2752 * Default constructor.
2753 */
2754 StrBuilderWriter() {
2755 super();
2756 }
2757
2758 /** {@inheritDoc} */
2759 public void close() {
2760 // do nothing
2761 }
2762
2763 /** {@inheritDoc} */
2764 public void flush() {
2765 // do nothing
2766 }
2767
2768 /** {@inheritDoc} */
2769 public void write(int c) {
2770 StrBuilder.this.append((char) c);
2771 }
2772
2773 /** {@inheritDoc} */
2774 public void write(char[] cbuf) {
2775 StrBuilder.this.append(cbuf);
2776 }
2777
2778 /** {@inheritDoc} */
2779 public void write(char[] cbuf, int off, int len) {
2780 StrBuilder.this.append(cbuf, off, len);
2781 }
2782
2783 /** {@inheritDoc} */
2784 public void write(String str) {
2785 StrBuilder.this.append(str);
2786 }
2787
2788 /** {@inheritDoc} */
2789 public void write(String str, int off, int len) {
2790 StrBuilder.this.append(str, off, len);
2791 }
2792 }
2793
2794}
Note: See TracBrowser for help on using the repository browser.