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