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