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