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