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    *      https://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                 final int toIndex = size + padLen;
911                 Arrays.fill(buffer, size, toIndex, padChar);
912                 str.getChars(0, strLen, buffer, toIndex);
913             }
914             size += width;
915         }
916         return this;
917     }
918 
919     /**
920      * Appends an object to the builder padding on the right to a fixed length. The {@code String.valueOf} of the
921      * {@code int} value is used. If the object is larger than the length, the right hand side is lost.
922      *
923      * @param value the value to append
924      * @param width the fixed field width, zero or negative has no effect
925      * @param padChar the pad character to use
926      * @return this, to enable chaining
927      */
928     public TextStringBuilder appendFixedWidthPadRight(final int value, final int width, final char padChar) {
929         return appendFixedWidthPadRight(String.valueOf(value), width, padChar);
930     }
931 
932     /**
933      * Appends an object to the builder padding on the right to a fixed length. The {@code toString} of the object is
934      * used. If the object is larger than the length, the right hand side is lost. If the object is null, null text
935      * value is used.
936      *
937      * @param obj the object to append, null uses null text
938      * @param width the fixed field width, zero or negative has no effect
939      * @param padChar the pad character to use
940      * @return this, to enable chaining
941      */
942     public TextStringBuilder appendFixedWidthPadRight(final Object obj, final int width, final char padChar) {
943         if (width > 0) {
944             ensureCapacityInternal(size + width);
945             String str = Objects.toString(obj, getNullText());
946             if (str == null) {
947                 str = StringUtils.EMPTY;
948             }
949             final int strLen = str.length();
950             if (strLen >= width) {
951                 str.getChars(0, width, buffer, size);
952             } else {
953                 str.getChars(0, strLen, buffer, size);
954                 final int fromIndex = size + strLen;
955                 Arrays.fill(buffer, fromIndex, fromIndex + width - strLen, padChar);
956             }
957             size += width;
958         }
959         return this;
960     }
961 
962     /**
963      * Appends a boolean value followed by a new line to the string builder.
964      *
965      * @param value the value to append
966      * @return this, to enable chaining
967      */
968     public TextStringBuilder appendln(final boolean value) {
969         return append(value).appendNewLine();
970     }
971 
972     /**
973      * Appends a char value followed by a new line to the string builder.
974      *
975      * @param ch the value to append
976      * @return this, to enable chaining
977      */
978     public TextStringBuilder appendln(final char ch) {
979         return append(ch).appendNewLine();
980     }
981 
982     /**
983      * Appends a char array followed by a new line to the string builder. Appending null will call
984      * {@link #appendNull()}.
985      *
986      * @param chars the char array to append
987      * @return this, to enable chaining
988      */
989     public TextStringBuilder appendln(final char[] chars) {
990         return append(chars).appendNewLine();
991     }
992 
993     /**
994      * Appends a char array followed by a new line to the string builder. Appending null will call
995      * {@link #appendNull()}.
996      *
997      * @param chars the char array to append
998      * @param startIndex the start index, inclusive, must be valid
999      * @param length the length to append, must be valid
1000      * @return this, to enable chaining
1001      */
1002     public TextStringBuilder appendln(final char[] chars, final int startIndex, final int length) {
1003         return append(chars, startIndex, length).appendNewLine();
1004     }
1005 
1006     /**
1007      * Appends a double value followed by a new line to the string builder using {@code String.valueOf}.
1008      *
1009      * @param value the value to append
1010      * @return this, to enable chaining
1011      */
1012     public TextStringBuilder appendln(final double value) {
1013         return append(value).appendNewLine();
1014     }
1015 
1016     /**
1017      * Appends a float value followed by a new line to the string builder using {@code String.valueOf}.
1018      *
1019      * @param value the value to append
1020      * @return this, to enable chaining
1021      */
1022     public TextStringBuilder appendln(final float value) {
1023         return append(value).appendNewLine();
1024     }
1025 
1026     /**
1027      * Appends an int value followed by a new line to the string builder using {@code String.valueOf}.
1028      *
1029      * @param value the value to append
1030      * @return this, to enable chaining
1031      */
1032     public TextStringBuilder appendln(final int value) {
1033         return append(value).appendNewLine();
1034     }
1035 
1036     /**
1037      * Appends a long value followed by a new line to the string builder using {@code String.valueOf}.
1038      *
1039      * @param value the value to append
1040      * @return this, to enable chaining
1041      */
1042     public TextStringBuilder appendln(final long value) {
1043         return append(value).appendNewLine();
1044     }
1045 
1046     /**
1047      * Appends an object followed by a new line to this string builder. Appending null will call {@link #appendNull()}.
1048      *
1049      * @param obj the object to append
1050      * @return this, to enable chaining
1051      */
1052     public TextStringBuilder appendln(final Object obj) {
1053         return append(obj).appendNewLine();
1054     }
1055 
1056     /**
1057      * Appends a string followed by a new line to this string builder. Appending null will call {@link #appendNull()}.
1058      *
1059      * @param str the string to append
1060      * @return this, to enable chaining
1061      */
1062     public TextStringBuilder appendln(final String str) {
1063         return append(str).appendNewLine();
1064     }
1065 
1066     /**
1067      * Appends part of a string followed by a new line to this string builder. Appending null will call
1068      * {@link #appendNull()}.
1069      *
1070      * @param str the string to append
1071      * @param startIndex the start index, inclusive, must be valid
1072      * @param length the length to append, must be valid
1073      * @return this, to enable chaining
1074      */
1075     public TextStringBuilder appendln(final String str, final int startIndex, final int length) {
1076         return append(str, startIndex, length).appendNewLine();
1077     }
1078 
1079     /**
1080      * Calls {@link String#format(String, Object...)} and appends the result.
1081      *
1082      * @param format the format string
1083      * @param objs the objects to use in the format string
1084      * @return {@code this} to enable chaining
1085      * @see String#format(String, Object...)
1086      */
1087     public TextStringBuilder appendln(final String format, final Object... objs) {
1088         return append(format, objs).appendNewLine();
1089     }
1090 
1091     /**
1092      * Appends a string buffer followed by a new line to this string builder. Appending null will call
1093      * {@link #appendNull()}.
1094      *
1095      * @param str the string buffer to append
1096      * @return this, to enable chaining
1097      */
1098     public TextStringBuilder appendln(final StringBuffer str) {
1099         return append(str).appendNewLine();
1100     }
1101 
1102     /**
1103      * Appends part of a string buffer followed by a new line to this string builder. Appending null will call
1104      * {@link #appendNull()}.
1105      *
1106      * @param str the string to append
1107      * @param startIndex the start index, inclusive, must be valid
1108      * @param length the length to append, must be valid
1109      * @return this, to enable chaining
1110      */
1111     public TextStringBuilder appendln(final StringBuffer str, final int startIndex, final int length) {
1112         return append(str, startIndex, length).appendNewLine();
1113     }
1114 
1115     /**
1116      * Appends a string builder followed by a new line to this string builder. Appending null will call
1117      * {@link #appendNull()}.
1118      *
1119      * @param str the string builder to append
1120      * @return this, to enable chaining
1121      */
1122     public TextStringBuilder appendln(final StringBuilder str) {
1123         return append(str).appendNewLine();
1124     }
1125 
1126     /**
1127      * Appends part of a string builder followed by a new line to this string builder. Appending null will call
1128      * {@link #appendNull()}.
1129      *
1130      * @param str the string builder to append
1131      * @param startIndex the start index, inclusive, must be valid
1132      * @param length the length to append, must be valid
1133      * @return this, to enable chaining
1134      */
1135     public TextStringBuilder appendln(final StringBuilder str, final int startIndex, final int length) {
1136         return append(str, startIndex, length).appendNewLine();
1137     }
1138 
1139     /**
1140      * Appends another string builder followed by a new line to this string builder. Appending null will call
1141      * {@link #appendNull()}.
1142      *
1143      * @param str the string builder to append
1144      * @return this, to enable chaining
1145      */
1146     public TextStringBuilder appendln(final TextStringBuilder str) {
1147         return append(str).appendNewLine();
1148     }
1149 
1150     /**
1151      * Appends part of a string builder followed by a new line to this string builder. Appending null will call
1152      * {@link #appendNull()}.
1153      *
1154      * @param str the string to append
1155      * @param startIndex the start index, inclusive, must be valid
1156      * @param length the length to append, must be valid
1157      * @return this, to enable chaining
1158      */
1159     public TextStringBuilder appendln(final TextStringBuilder str, final int startIndex, final int length) {
1160         return append(str, startIndex, length).appendNewLine();
1161     }
1162 
1163     /**
1164      * Appends this builder's new line string to this builder.
1165      * <p>
1166      * By default, the new line is the system default from {@link System#lineSeparator()}.
1167      * </p>
1168      * <p>
1169      * 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
1170      * endings even when on Windows.
1171      * </p>
1172      *
1173      * @return this
1174      * @see #getNewLineText()
1175      * @see #setNewLineText(String)
1176      */
1177     public TextStringBuilder appendNewLine() {
1178         if (newLine == null) {
1179             append(System.lineSeparator());
1180             return this;
1181         }
1182         return append(newLine);
1183     }
1184 
1185     /**
1186      * Appends the text representing {@code null} to this string builder.
1187      *
1188      * @return this, to enable chaining
1189      */
1190     public TextStringBuilder appendNull() {
1191         if (nullText == null) {
1192             return this;
1193         }
1194         return append(nullText);
1195     }
1196 
1197     /**
1198      * Appends the pad character to the builder the specified number of times.
1199      *
1200      * @param length the length to append, negative means no append
1201      * @param padChar the character to append
1202      * @return this, to enable chaining
1203      */
1204     public TextStringBuilder appendPadding(final int length, final char padChar) {
1205         if (length >= 0) {
1206             ensureCapacityInternal(size + length);
1207             for (int i = 0; i < length; i++) {
1208                 buffer[size++] = padChar;
1209             }
1210         }
1211         return this;
1212     }
1213 
1214     /**
1215      * Appends a separator if the builder is currently non-empty. The separator is appended using {@link #append(char)}.
1216      * <p>
1217      * This method is useful for adding a separator each time around the loop except the first.
1218      * </p>
1219      *
1220      * <pre>
1221      * for (Iterator it = list.iterator(); it.hasNext();) {
1222      *     appendSeparator(',');
1223      *     append(it.next());
1224      * }
1225      * </pre>
1226      *
1227      * <p>
1228      * Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}.
1229      * </p>
1230      *
1231      * @param separator the separator to use
1232      * @return this, to enable chaining
1233      */
1234     public TextStringBuilder appendSeparator(final char separator) {
1235         if (isNotEmpty()) {
1236             append(separator);
1237         }
1238         return this;
1239     }
1240 
1241     /**
1242      * Appends one of both separators to the builder If the builder is currently empty it will append the
1243      * defaultIfEmpty-separator Otherwise it will append the standard-separator
1244      *
1245      * The separator is appended using {@link #append(char)}.
1246      *
1247      * @param standard the separator if builder is not empty
1248      * @param defaultIfEmpty the separator if builder is empty
1249      * @return this, to enable chaining
1250      */
1251     public TextStringBuilder appendSeparator(final char standard, final char defaultIfEmpty) {
1252         if (isEmpty()) {
1253             append(defaultIfEmpty);
1254         } else {
1255             append(standard);
1256         }
1257         return this;
1258     }
1259 
1260     /**
1261      * Appends a separator to the builder if the loop index is greater than zero. The separator is appended using
1262      * {@link #append(char)}.
1263      * <p>
1264      * This method is useful for adding a separator each time around the loop except the first.
1265      * </p>
1266      *
1267      * <pre>
1268      * for (int i = 0; i &lt; list.size(); i++) {
1269      *     appendSeparator(",", i);
1270      *     append(list.get(i));
1271      * }
1272      * </pre>
1273      *
1274      * <p>
1275      * Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}.
1276      * </p>
1277      *
1278      * @param separator the separator to use
1279      * @param loopIndex the loop index
1280      * @return this, to enable chaining
1281      */
1282     public TextStringBuilder appendSeparator(final char separator, final int loopIndex) {
1283         if (loopIndex > 0) {
1284             append(separator);
1285         }
1286         return this;
1287     }
1288 
1289     /**
1290      * Appends a separator if the builder is currently non-empty. Appending a null separator will have no effect. The
1291      * separator is appended using {@link #append(String)}.
1292      * <p>
1293      * This method is useful for adding a separator each time around the loop except the first.
1294      * </p>
1295      *
1296      * <pre>
1297      * for (Iterator it = list.iterator(); it.hasNext();) {
1298      *     appendSeparator(",");
1299      *     append(it.next());
1300      * }
1301      * </pre>
1302      *
1303      * <p>
1304      * Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}.
1305      * </p>
1306      *
1307      * @param separator the separator to use, null means no separator
1308      * @return this, to enable chaining
1309      */
1310     public TextStringBuilder appendSeparator(final String separator) {
1311         return appendSeparator(separator, null);
1312     }
1313 
1314     /**
1315      * Appends a separator to the builder if the loop index is greater than zero. Appending a null separator will have
1316      * no effect. The separator is appended using {@link #append(String)}.
1317      * <p>
1318      * This method is useful for adding a separator each time around the loop except the first.
1319      * </p>
1320      *
1321      * <pre>
1322      * for (int i = 0; i &lt; list.size(); i++) {
1323      *     appendSeparator(",", i);
1324      *     append(list.get(i));
1325      * }
1326      * </pre>
1327      *
1328      * <p>
1329      * Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}.
1330      * </p>
1331      *
1332      * @param separator the separator to use, null means no separator
1333      * @param loopIndex the loop index
1334      * @return this, to enable chaining
1335      */
1336     public TextStringBuilder appendSeparator(final String separator, final int loopIndex) {
1337         if (separator != null && loopIndex > 0) {
1338             append(separator);
1339         }
1340         return this;
1341     }
1342 
1343     /**
1344      * Appends one of both separators to the StrBuilder. If the builder is currently empty, it will append the
1345      * defaultIfEmpty-separator, otherwise it will append the standard-separator.
1346      * <p>
1347      * Appending a null separator will have no effect. The separator is appended using {@link #append(String)}.
1348      * </p>
1349      * <p>
1350      * This method is for example useful for constructing queries
1351      * </p>
1352      *
1353      * <pre>
1354      * StrBuilder whereClause = new StrBuilder();
1355      * if (searchCommand.getPriority() != null) {
1356      *  whereClause.appendSeparator(" and", " where");
1357      *  whereClause.append(" priority = ?")
1358      * }
1359      * if (searchCommand.getComponent() != null) {
1360      *  whereClause.appendSeparator(" and", " where");
1361      *  whereClause.append(" component = ?")
1362      * }
1363      * selectClause.append(whereClause)
1364      * </pre>
1365      *
1366      * @param standard the separator if builder is not empty, null means no separator
1367      * @param defaultIfEmpty the separator if builder is empty, null means no separator
1368      * @return this, to enable chaining
1369      */
1370     public TextStringBuilder appendSeparator(final String standard, final String defaultIfEmpty) {
1371         final String str = isEmpty() ? defaultIfEmpty : standard;
1372         if (str != null) {
1373             append(str);
1374         }
1375         return this;
1376     }
1377 
1378     /**
1379      * Appends current contents of this {@code StrBuilder} to the provided {@link Appendable}.
1380      * <p>
1381      * This method tries to avoid doing any extra copies of contents.
1382      * </p>
1383      *
1384      * @param appendable the appendable to append data to
1385      * @throws IOException if an I/O error occurs.
1386      * @see #readFrom(Readable)
1387      */
1388     public void appendTo(final Appendable appendable) throws IOException {
1389         if (appendable instanceof Writer) {
1390             ((Writer) appendable).write(buffer, 0, size);
1391         } else if (appendable instanceof StringBuilder) {
1392             ((StringBuilder) appendable).append(buffer, 0, size);
1393         } else if (appendable instanceof StringBuffer) {
1394             ((StringBuffer) appendable).append(buffer, 0, size);
1395         } else if (appendable instanceof CharBuffer) {
1396             ((CharBuffer) appendable).put(buffer, 0, size);
1397         } else {
1398             appendable.append(this);
1399         }
1400     }
1401 
1402     /** Appends {@code "true"}. */
1403     private void appendTrue(int index) {
1404         buffer[index++] = 't';
1405         buffer[index++] = 'r';
1406         buffer[index++] = 'u';
1407         buffer[index] = 'e';
1408         size += TRUE_STRING_SIZE;
1409     }
1410 
1411     /**
1412      * Appends an iterable placing separators between each value, but not before the first or after the last. Appending
1413      * a null iterable will have no effect. Each object is appended using {@link #append(Object)}.
1414      *
1415      * @param iterable the iterable to append
1416      * @param separator the separator to use, null means no separator
1417      * @return this, to enable chaining
1418      */
1419     public TextStringBuilder appendWithSeparators(final Iterable<?> iterable, final String separator) {
1420         if (iterable != null) {
1421             appendWithSeparators(iterable.iterator(), separator);
1422         }
1423         return this;
1424     }
1425 
1426     /**
1427      * Appends an iterator placing separators between each value, but not before the first or after the last. Appending
1428      * a null iterator will have no effect. Each object is appended using {@link #append(Object)}.
1429      *
1430      * @param it the iterator to append
1431      * @param separator the separator to use, null means no separator
1432      * @return this, to enable chaining
1433      */
1434     public TextStringBuilder appendWithSeparators(final Iterator<?> it, final String separator) {
1435         if (it != null) {
1436             final String sep = Objects.toString(separator, StringUtils.EMPTY);
1437             while (it.hasNext()) {
1438                 append(it.next());
1439                 if (it.hasNext()) {
1440                     append(sep);
1441                 }
1442             }
1443         }
1444         return this;
1445     }
1446 
1447     /**
1448      * Appends an array placing separators between each value, but not before the first or after the last. Appending a
1449      * null array will have no effect. Each object is appended using {@link #append(Object)}.
1450      *
1451      * @param array the array to append
1452      * @param separator the separator to use, null means no separator
1453      * @return this, to enable chaining
1454      */
1455     public TextStringBuilder appendWithSeparators(final Object[] array, final String separator) {
1456         if (array != null && array.length > 0) {
1457             final String sep = Objects.toString(separator, StringUtils.EMPTY);
1458             append(array[0]);
1459             for (int i = 1; i < array.length; i++) {
1460                 append(sep);
1461                 append(array[i]);
1462             }
1463         }
1464         return this;
1465     }
1466 
1467     /**
1468      * Gets the contents of this builder as a Reader.
1469      * <p>
1470      * This method allows the contents of the builder to be read using any standard method that expects a Reader.
1471      * </p>
1472      * <p>
1473      * To use, simply create a {@code StrBuilder}, populate it with data, call {@code asReader}, and then read away.
1474      * </p>
1475      * <p>
1476      * The internal character array is shared between the builder and the reader. This allows you to append to the
1477      * builder after creating the reader, and the changes will be picked up. Note however, that no synchronization
1478      * occurs, so you must perform all operations with the builder and the reader in one thread.
1479      * </p>
1480      * <p>
1481      * The returned reader supports marking, and ignores the flush method.
1482      * </p>
1483      *
1484      * @return a reader that reads from this builder
1485      */
1486     public Reader asReader() {
1487         return new TextStringBuilderReader();
1488     }
1489 
1490     /**
1491      * Creates a tokenizer that can tokenize the contents of this builder.
1492      * <p>
1493      * This method allows the contents of this builder to be tokenized. The tokenizer will be setup by default to
1494      * tokenize on space, tab, newline and form feed (as per StringTokenizer). These values can be changed on the
1495      * tokenizer class, before retrieving the tokens.
1496      * </p>
1497      * <p>
1498      * The returned tokenizer is linked to this builder. You may intermix calls to the builder and tokenizer within
1499      * certain limits, however there is no synchronization. Once the tokenizer has been used once, it must be
1500      * {@link StringTokenizer#reset() reset} to pickup the latest changes in the builder. For example:
1501      * </p>
1502      *
1503      * <pre>
1504      * StrBuilder b = new StrBuilder();
1505      * b.append("a b ");
1506      * StrTokenizer t = b.asTokenizer();
1507      * String[] tokens1 = t.getTokenArray(); // returns a,b
1508      * b.append("c d ");
1509      * String[] tokens2 = t.getTokenArray(); // returns a,b (c and d ignored)
1510      * t.reset(); // reset causes builder changes to be picked up
1511      * String[] tokens3 = t.getTokenArray(); // returns a,b,c,d
1512      * </pre>
1513      *
1514      * <p>
1515      * In addition to simply intermixing appends and tokenization, you can also call the set methods on the tokenizer to
1516      * alter how it tokenizes. Just remember to call reset when you want to pickup builder changes.
1517      * </p>
1518      * <p>
1519      * Calling {@link StringTokenizer#reset(String)} or {@link StringTokenizer#reset(char[])} with a non-null value will
1520      * break the link with the builder.
1521      * </p>
1522      *
1523      * @return a tokenizer that is linked to this builder
1524      */
1525     public StringTokenizer asTokenizer() {
1526         return new TextStringBuilderTokenizer();
1527     }
1528 
1529     /**
1530      * Gets this builder as a Writer that can be written to.
1531      * <p>
1532      * This method allows you to populate the contents of the builder using any standard method that takes a Writer.
1533      * </p>
1534      * <p>
1535      * To use, simply create a {@code StrBuilder}, call {@code asWriter}, and populate away. The data is available at
1536      * any time using the methods of the {@code StrBuilder}.
1537      * </p>
1538      * <p>
1539      * The internal character array is shared between the builder and the writer. This allows you to intermix calls that
1540      * append to the builder and write using the writer and the changes will be occur correctly. Note however, that no
1541      * synchronization occurs, so you must perform all operations with the builder and the writer in one thread.
1542      * </p>
1543      * <p>
1544      * The returned writer ignores the close and flush methods.
1545      * </p>
1546      *
1547      * @return a writer that populates this builder
1548      */
1549     public Writer asWriter() {
1550         return new TextStringBuilderWriter();
1551     }
1552 
1553     /**
1554      * Converts this instance to a String.
1555      *
1556      * @return This instance as a String
1557      * @see #toString()
1558      * @deprecated Use {@link #get()}.
1559      */
1560     @Deprecated
1561     @Override
1562     public String build() {
1563         return toString();
1564     }
1565 
1566     /**
1567      * Gets the current size of the internal character array buffer.
1568      *
1569      * @return The capacity
1570      */
1571     public int capacity() {
1572         return buffer.length;
1573     }
1574 
1575     /**
1576      * Gets the character at the specified index.
1577      *
1578      * @see #setCharAt(int, char)
1579      * @see #deleteCharAt(int)
1580      * @param index the index to retrieve, must be valid
1581      * @return The character at the index
1582      * @throws IndexOutOfBoundsException if the index is invalid
1583      */
1584     @Override
1585     public char charAt(final int index) {
1586         validateIndex(index);
1587         return buffer[index];
1588     }
1589 
1590     /**
1591      * Clears the string builder (convenience Collections API style method).
1592      * <p>
1593      * This method does not reduce the size of the internal character buffer. To do that, call {@code clear()} followed
1594      * by {@link #minimizeCapacity()}.
1595      * </p>
1596      * <p>
1597      * This method is the same as {@link #setLength(int)} called with zero and is provided to match the API of
1598      * Collections.
1599      * </p>
1600      *
1601      * @return this, to enable chaining
1602      */
1603     public TextStringBuilder clear() {
1604         size = 0;
1605         return this;
1606     }
1607 
1608     /**
1609      * Tests if the string builder contains the specified char.
1610      *
1611      * @param ch the character to find
1612      * @return true if the builder contains the character
1613      */
1614     public boolean contains(final char ch) {
1615         final char[] thisBuf = buffer;
1616         for (int i = 0; i < this.size; i++) {
1617             if (thisBuf[i] == ch) {
1618                 return true;
1619             }
1620         }
1621         return false;
1622     }
1623 
1624     /**
1625      * Tests if the string builder contains the specified string.
1626      *
1627      * @param str the string to find
1628      * @return true if the builder contains the string
1629      */
1630     public boolean contains(final String str) {
1631         return indexOf(str, 0) >= 0;
1632     }
1633 
1634     /**
1635      * Tests if the string builder contains a string matched using the specified matcher.
1636      * <p>
1637      * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to search for
1638      * the character 'a' followed by a number.
1639      * </p>
1640      *
1641      * @param matcher the matcher to use, null returns -1
1642      * @return true if the matcher finds a match in the builder
1643      */
1644     public boolean contains(final StringMatcher matcher) {
1645         return indexOf(matcher, 0) >= 0;
1646     }
1647 
1648     /**
1649      * Deletes the characters between the two specified indices.
1650      *
1651      * @param startIndex the start index, inclusive, must be valid
1652      * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string
1653      * @return this, to enable chaining
1654      * @throws IndexOutOfBoundsException if the index is invalid
1655      */
1656     public TextStringBuilder delete(final int startIndex, final int endIndex) {
1657         final int actualEndIndex = validateRange(startIndex, endIndex);
1658         final int len = actualEndIndex - startIndex;
1659         if (len > 0) {
1660             deleteImpl(startIndex, actualEndIndex, len);
1661         }
1662         return this;
1663     }
1664 
1665     /**
1666      * Deletes the character wherever it occurs in the builder.
1667      *
1668      * @param ch the character to delete
1669      * @return this, to enable chaining
1670      */
1671     public TextStringBuilder deleteAll(final char ch) {
1672         for (int i = 0; i < size; i++) {
1673             if (buffer[i] == ch) {
1674                 final int start = i;
1675                 while (++i < size) {
1676                     if (buffer[i] != ch) {
1677                         break;
1678                     }
1679                 }
1680                 final int len = i - start;
1681                 deleteImpl(start, i, len);
1682                 i -= len;
1683             }
1684         }
1685         return this;
1686     }
1687 
1688     /**
1689      * Deletes the string wherever it occurs in the builder.
1690      *
1691      * @param str the string to delete, null causes no action
1692      * @return this, to enable chaining
1693      */
1694     public TextStringBuilder deleteAll(final String str) {
1695         final int len = str == null ? 0 : str.length();
1696         if (len > 0) {
1697             int index = indexOf(str, 0);
1698             while (index >= 0) {
1699                 deleteImpl(index, index + len, len);
1700                 index = indexOf(str, index);
1701             }
1702         }
1703         return this;
1704     }
1705 
1706     /**
1707      * Deletes all parts of the builder that the matcher matches.
1708      * <p>
1709      * Matchers can be used to perform advanced deletion behavior. For example you could write a matcher to delete all
1710      * occurrences where the character 'a' is followed by a number.
1711      * </p>
1712      *
1713      * @param matcher the matcher to use to find the deletion, null causes no action
1714      * @return this, to enable chaining
1715      */
1716     public TextStringBuilder deleteAll(final StringMatcher matcher) {
1717         return replace(matcher, null, 0, size, -1);
1718     }
1719 
1720     /**
1721      * Deletes the character at the specified index.
1722      *
1723      * @see #charAt(int)
1724      * @see #setCharAt(int, char)
1725      * @param index the index to delete
1726      * @return this, to enable chaining
1727      * @throws IndexOutOfBoundsException if the index is invalid
1728      */
1729     public TextStringBuilder deleteCharAt(final int index) {
1730         validateIndex(index);
1731         deleteImpl(index, index + 1, 1);
1732         return this;
1733     }
1734 
1735     /**
1736      * Deletes the character wherever it occurs in the builder.
1737      *
1738      * @param ch the character to delete
1739      * @return this, to enable chaining
1740      */
1741     public TextStringBuilder deleteFirst(final char ch) {
1742         for (int i = 0; i < size; i++) {
1743             if (buffer[i] == ch) {
1744                 deleteImpl(i, i + 1, 1);
1745                 break;
1746             }
1747         }
1748         return this;
1749     }
1750 
1751     /**
1752      * Deletes the string wherever it occurs in the builder.
1753      *
1754      * @param str the string to delete, null causes no action
1755      * @return this, to enable chaining
1756      */
1757     public TextStringBuilder deleteFirst(final String str) {
1758         final int len = str == null ? 0 : str.length();
1759         if (len > 0) {
1760             final int index = indexOf(str, 0);
1761             if (index >= 0) {
1762                 deleteImpl(index, index + len, len);
1763             }
1764         }
1765         return this;
1766     }
1767 
1768     /**
1769      * Deletes the first match within the builder using the specified matcher.
1770      * <p>
1771      * Matchers can be used to perform advanced deletion behavior. For example you could write a matcher to delete where
1772      * the character 'a' is followed by a number.
1773      * </p>
1774      *
1775      * @param matcher the matcher to use to find the deletion, null causes no action
1776      * @return this, to enable chaining
1777      */
1778     public TextStringBuilder deleteFirst(final StringMatcher matcher) {
1779         return replace(matcher, null, 0, size, 1);
1780     }
1781 
1782     /**
1783      * Internal method to delete a range without validation.
1784      *
1785      * @param startIndex the start index, must be valid
1786      * @param endIndex the end index (exclusive), must be valid
1787      * @param len the length, must be valid
1788      * @throws IndexOutOfBoundsException if any index is invalid
1789      */
1790     private void deleteImpl(final int startIndex, final int endIndex, final int len) {
1791         System.arraycopy(buffer, endIndex, buffer, startIndex, size - endIndex);
1792         size -= len;
1793     }
1794 
1795     /**
1796      * Gets the character at the specified index before deleting it.
1797      *
1798      * @see #charAt(int)
1799      * @see #deleteCharAt(int)
1800      * @param index the index to retrieve, must be valid
1801      * @return The character at the index
1802      * @throws IndexOutOfBoundsException if the index is invalid
1803      * @since 1.9
1804      */
1805     public char drainChar(final int index) {
1806         validateIndex(index);
1807         final char c = buffer[index];
1808         deleteCharAt(index);
1809         return c;
1810     }
1811 
1812     /**
1813      * Drains (copies, then deletes) this character sequence into the specified array. This is equivalent to copying the
1814      * characters from this sequence into the target and then deleting those character from this sequence.
1815      *
1816      * @param startIndex first index to copy, inclusive.
1817      * @param endIndex last index to copy, exclusive.
1818      * @param target the target array, must not be {@code null}.
1819      * @param targetIndex the index to start copying in the target.
1820      * @return How many characters where copied (then deleted). If this builder is empty, return {@code 0}.
1821      * @since 1.9
1822      */
1823     public int drainChars(final int startIndex, final int endIndex, final char[] target, final int targetIndex) {
1824         final int length = endIndex - startIndex;
1825         if (isEmpty() || length == 0 || target.length == 0) {
1826             return 0;
1827         }
1828         final int actualLen = Math.min(Math.min(size, length), target.length - targetIndex);
1829         getChars(startIndex, actualLen, target, targetIndex);
1830         delete(startIndex, actualLen);
1831         return actualLen;
1832     }
1833 
1834     /**
1835      * Checks whether this builder ends with the specified string.
1836      * <p>
1837      * Note that this method handles null input quietly, unlike String.
1838      * </p>
1839      *
1840      * @param str the string to search for, null returns false
1841      * @return true if the builder ends with the string
1842      */
1843     public boolean endsWith(final String str) {
1844         if (str == null) {
1845             return false;
1846         }
1847         final int len = str.length();
1848         if (len == 0) {
1849             return true;
1850         }
1851         if (len > size) {
1852             return false;
1853         }
1854         int pos = size - len;
1855         for (int i = 0; i < len; i++, pos++) {
1856             if (buffer[pos] != str.charAt(i)) {
1857                 return false;
1858             }
1859         }
1860         return true;
1861     }
1862 
1863     /**
1864      * Tests the capacity and ensures that it is at least the size specified.
1865      *
1866      * <p>
1867      * Note: This method can be used to minimise memory reallocations during
1868      * repeated addition of values by pre-allocating the character buffer.
1869      * The method ignores a negative {@code capacity} argument.
1870      * </p>
1871      *
1872      * @param capacity the capacity to ensure
1873      * @return this, to enable chaining
1874      * @throws OutOfMemoryError if the capacity cannot be allocated
1875      */
1876     public TextStringBuilder ensureCapacity(final int capacity) {
1877         if (capacity > 0) {
1878             ensureCapacityInternal(capacity);
1879         }
1880         return this;
1881     }
1882 
1883     /**
1884      * Ensures that the buffer is at least the size specified. The {@code capacity} argument
1885      * is treated as an unsigned integer.
1886      *
1887      * <p>
1888      * This method will raise an {@link OutOfMemoryError} if the capacity is too large
1889      * for an array, or cannot be allocated.
1890      * </p>
1891      *
1892      * @param capacity the capacity to ensure
1893      * @throws OutOfMemoryError if the capacity cannot be allocated
1894      */
1895     private void ensureCapacityInternal(final int capacity) {
1896         // Check for overflow of the current buffer.
1897         // Assumes capacity is an unsigned integer up to Integer.MAX_VALUE * 2
1898         // (the largest possible addition of two maximum length arrays).
1899         if (capacity - buffer.length > 0) {
1900             resizeBuffer(capacity);
1901         }
1902     }
1903 
1904     /**
1905      * Tests the contents of this builder against another to see if they contain the same character content.
1906      *
1907      * @param obj the object to check, null returns false
1908      * @return true if the builders contain the same characters in the same order
1909      */
1910     @Override
1911     public boolean equals(final Object obj) {
1912         return obj instanceof TextStringBuilder && equals((TextStringBuilder) obj);
1913     }
1914 
1915     /**
1916      * Tests the contents of this builder against another to see if they contain the same character content.
1917      *
1918      * @param other the object to check, null returns false
1919      * @return true if the builders contain the same characters in the same order
1920      */
1921     public boolean equals(final TextStringBuilder other) {
1922         if (this == other) {
1923             return true;
1924         }
1925         if (other == null) {
1926             return false;
1927         }
1928         if (this.size != other.size) {
1929             return false;
1930         }
1931         // Be aware not to use Arrays.equals(buffer, other.buffer) for equals() method
1932         // as length of the buffers may be different (TEXT-211)
1933         final char[] thisBuf = this.buffer;
1934         final char[] otherBuf = other.buffer;
1935         for (int i = size - 1; i >= 0; i--) {
1936             if (thisBuf[i] != otherBuf[i]) {
1937                 return false;
1938             }
1939         }
1940         return true;
1941     }
1942 
1943     /**
1944      * Tests the contents of this builder against another to see if they contain the same character content ignoring
1945      * case.
1946      *
1947      * @param other the object to check, null returns false
1948      * @return true if the builders contain the same characters in the same order
1949      */
1950     public boolean equalsIgnoreCase(final TextStringBuilder other) {
1951         if (this == other) {
1952             return true;
1953         }
1954         if (this.size != other.size) {
1955             return false;
1956         }
1957         final char[] thisBuf = this.buffer;
1958         final char[] otherBuf = other.buffer;
1959         for (int i = size - 1; i >= 0; i--) {
1960             final char c1 = thisBuf[i];
1961             final char c2 = otherBuf[i];
1962             if (c1 != c2 && Character.toUpperCase(c1) != Character.toUpperCase(c2)) {
1963                 return false;
1964             }
1965         }
1966         return true;
1967     }
1968 
1969     /**
1970      * Converts this instance to a String.
1971      *
1972      * @return This instance as a String
1973      * @see #toString()
1974      * @since 1.12.0
1975      */
1976     @Override
1977     public String get() {
1978         return toString();
1979     }
1980 
1981     /**
1982      * Gets a direct reference to internal storage, not for public consumption.
1983      */
1984     char[] getBuffer() {
1985         return buffer;
1986     }
1987 
1988     /**
1989      * Copies this character array into the specified array.
1990      *
1991      * @param target the target array, null will cause an array to be created
1992      * @return The input array, unless that was null or too small
1993      */
1994     public char[] getChars(char[] target) {
1995         final int len = length();
1996         if (target == null || target.length < len) {
1997             target = new char[len];
1998         }
1999         System.arraycopy(buffer, 0, target, 0, len);
2000         return target;
2001     }
2002 
2003     /**
2004      * Copies this character array into the specified array.
2005      *
2006      * @param startIndex first index to copy, inclusive, must be valid.
2007      * @param endIndex last index to copy, exclusive, must be valid.
2008      * @param target the target array, must not be null or too small.
2009      * @param targetIndex the index to start copying in target.
2010      * @throws NullPointerException if the array is null.
2011      * @throws IndexOutOfBoundsException if any index is invalid.
2012      */
2013     public void getChars(final int startIndex, final int endIndex, final char[] target, final int targetIndex) {
2014         if (startIndex < 0) {
2015             throw new StringIndexOutOfBoundsException(startIndex);
2016         }
2017         if (endIndex < 0 || endIndex > length()) {
2018             throw new StringIndexOutOfBoundsException(endIndex);
2019         }
2020         if (startIndex > endIndex) {
2021             throw new StringIndexOutOfBoundsException("end < start");
2022         }
2023         System.arraycopy(buffer, startIndex, target, targetIndex, endIndex - startIndex);
2024     }
2025 
2026     /**
2027      * Gets the text to be appended when a {@link #appendNewLine() new line} is added.
2028      *
2029      * @return The new line text, {@code null} means use the system default from {@link System#lineSeparator()}.
2030      */
2031     public String getNewLineText() {
2032         return newLine;
2033     }
2034 
2035     /**
2036      * Gets the text to be appended when null is added.
2037      *
2038      * @return The null text, null means no append
2039      */
2040     public String getNullText() {
2041         return nullText;
2042     }
2043 
2044     /**
2045      * Gets a suitable hash code for this builder.
2046      *
2047      * @return a hash code
2048      */
2049     @Override
2050     public int hashCode() {
2051         // no allocation
2052         final char[] buf = buffer;
2053         int result = 0;
2054         for (int i = 0; i < size; i++) {
2055             result = 31 * result + buf[i];
2056         }
2057         return result;
2058     }
2059 
2060     /**
2061      * Searches the string builder to find the first reference to the specified char.
2062      *
2063      * @param ch the character to find
2064      * @return The first index of the character, or -1 if not found
2065      */
2066     public int indexOf(final char ch) {
2067         return indexOf(ch, 0);
2068     }
2069 
2070     /**
2071      * Searches the string builder to find the first reference to the specified char.
2072      *
2073      * @param ch the character to find
2074      * @param startIndex the index to start at, invalid index rounded to edge
2075      * @return The first index of the character, or -1 if not found
2076      */
2077     public int indexOf(final char ch, int startIndex) {
2078         startIndex = Math.max(0, startIndex);
2079         if (startIndex >= size) {
2080             return StringUtils.INDEX_NOT_FOUND;
2081         }
2082         final char[] thisBuf = buffer;
2083         for (int i = startIndex; i < size; i++) {
2084             if (thisBuf[i] == ch) {
2085                 return i;
2086             }
2087         }
2088         return StringUtils.INDEX_NOT_FOUND;
2089     }
2090 
2091     /**
2092      * Searches the string builder to find the first reference to the specified string.
2093      * <p>
2094      * Note that a null input string will return -1, whereas the JDK throws an exception.
2095      * </p>
2096      *
2097      * @param str the string to find, null returns -1
2098      * @return The first index of the string, or -1 if not found
2099      */
2100     public int indexOf(final String str) {
2101         return indexOf(str, 0);
2102     }
2103 
2104     /**
2105      * Searches the string builder to find the first reference to the specified string starting searching from the given
2106      * index.
2107      * <p>
2108      * Note that a null input string will return -1, whereas the JDK throws an exception.
2109      * </p>
2110      *
2111      * @param str the string to find, null returns -1
2112      * @param startIndex the index to start at, invalid index rounded to edge
2113      * @return The first index of the string, or -1 if not found
2114      */
2115     public int indexOf(final String str, int startIndex) {
2116         startIndex = Math.max(0, startIndex);
2117         if (str == null || startIndex >= size) {
2118             return StringUtils.INDEX_NOT_FOUND;
2119         }
2120         final int strLen = str.length();
2121         if (strLen == 1) {
2122             return indexOf(str.charAt(0), startIndex);
2123         }
2124         if (strLen == 0) {
2125             return startIndex;
2126         }
2127         if (strLen > size) {
2128             return StringUtils.INDEX_NOT_FOUND;
2129         }
2130         final char[] thisBuf = buffer;
2131         final int searchLen = size - strLen + 1;
2132         for (int i = startIndex; i < searchLen; i++) {
2133             boolean found = true;
2134             for (int j = 0; j < strLen && found; j++) {
2135                 found = str.charAt(j) == thisBuf[i + j];
2136             }
2137             if (found) {
2138                 return i;
2139             }
2140         }
2141         return StringUtils.INDEX_NOT_FOUND;
2142     }
2143 
2144     /**
2145      * Searches the string builder using the matcher to find the first match.
2146      * <p>
2147      * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the
2148      * character 'a' followed by a number.
2149      * </p>
2150      *
2151      * @param matcher the matcher to use, null returns -1
2152      * @return The first index matched, or -1 if not found
2153      */
2154     public int indexOf(final StringMatcher matcher) {
2155         return indexOf(matcher, 0);
2156     }
2157 
2158     /**
2159      * Searches the string builder using the matcher to find the first match searching from the given index.
2160      * <p>
2161      * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the
2162      * character 'a' followed by a number.
2163      * </p>
2164      *
2165      * @param matcher the matcher to use, null returns -1
2166      * @param startIndex the index to start at, invalid index rounded to edge
2167      * @return The first index matched, or -1 if not found
2168      */
2169     public int indexOf(final StringMatcher matcher, int startIndex) {
2170         startIndex = Math.max(0, startIndex);
2171         if (matcher == null || startIndex >= size) {
2172             return StringUtils.INDEX_NOT_FOUND;
2173         }
2174         final int len = size;
2175         final char[] buf = buffer;
2176         for (int i = startIndex; i < len; i++) {
2177             if (matcher.isMatch(buf, i, startIndex, len) > 0) {
2178                 return i;
2179             }
2180         }
2181         return StringUtils.INDEX_NOT_FOUND;
2182     }
2183 
2184     /**
2185      * Inserts the value into this builder.
2186      *
2187      * @param index the index to add at, must be valid
2188      * @param value the value to insert
2189      * @return this, to enable chaining
2190      * @throws IndexOutOfBoundsException if the index is invalid
2191      */
2192     public TextStringBuilder insert(final int index, final boolean value) {
2193         validateIndex(index);
2194         if (value) {
2195             ensureCapacityInternal(size + TRUE_STRING_SIZE);
2196             System.arraycopy(buffer, index, buffer, index + TRUE_STRING_SIZE, size - index);
2197             appendTrue(index);
2198         } else {
2199             ensureCapacityInternal(size + FALSE_STRING_SIZE);
2200             System.arraycopy(buffer, index, buffer, index + FALSE_STRING_SIZE, size - index);
2201             appendFalse(index);
2202         }
2203         return this;
2204     }
2205 
2206     /**
2207      * Inserts the value into this builder.
2208      *
2209      * @param index the index to add at, must be valid
2210      * @param value the value to insert
2211      * @return this, to enable chaining
2212      * @throws IndexOutOfBoundsException if the index is invalid
2213      */
2214     public TextStringBuilder insert(final int index, final char value) {
2215         validateIndex(index);
2216         ensureCapacityInternal(size + 1);
2217         System.arraycopy(buffer, index, buffer, index + 1, size - index);
2218         buffer[index] = value;
2219         size++;
2220         return this;
2221     }
2222 
2223     /**
2224      * Inserts the character array into this builder. Inserting null will use the stored null text value.
2225      *
2226      * @param index the index to add at, must be valid
2227      * @param chars the char array to insert
2228      * @return this, to enable chaining
2229      * @throws IndexOutOfBoundsException if the index is invalid
2230      */
2231     public TextStringBuilder insert(final int index, final char[] chars) {
2232         validateIndex(index);
2233         if (chars == null) {
2234             return insert(index, nullText);
2235         }
2236         final int len = chars.length;
2237         if (len > 0) {
2238             ensureCapacityInternal(size + len);
2239             System.arraycopy(buffer, index, buffer, index + len, size - index);
2240             System.arraycopy(chars, 0, buffer, index, len);
2241             size += len;
2242         }
2243         return this;
2244     }
2245 
2246     /**
2247      * Inserts part of the character array into this builder. Inserting null will use the stored null text value.
2248      *
2249      * @param index the index to add at, must be valid
2250      * @param chars the char array to insert
2251      * @param offset the offset into the character array to start at, must be valid
2252      * @param length the length of the character array part to copy, must be positive
2253      * @return this, to enable chaining
2254      * @throws IndexOutOfBoundsException if any index is invalid
2255      */
2256     public TextStringBuilder insert(final int index, final char[] chars, final int offset, final int length) {
2257         validateIndex(index);
2258         if (chars == null) {
2259             return insert(index, nullText);
2260         }
2261         if (offset < 0 || offset > chars.length) {
2262             throw new StringIndexOutOfBoundsException("Invalid offset: " + offset);
2263         }
2264         if (length < 0 || offset + length > chars.length) {
2265             throw new StringIndexOutOfBoundsException("Invalid length: " + length);
2266         }
2267         if (length > 0) {
2268             ensureCapacityInternal(size + length);
2269             System.arraycopy(buffer, index, buffer, index + length, size - index);
2270             System.arraycopy(chars, offset, buffer, index, length);
2271             size += length;
2272         }
2273         return this;
2274     }
2275 
2276     /**
2277      * Inserts the value into this builder.
2278      *
2279      * @param index the index to add at, must be valid
2280      * @param value the value to insert
2281      * @return this, to enable chaining
2282      * @throws IndexOutOfBoundsException if the index is invalid
2283      */
2284     public TextStringBuilder insert(final int index, final double value) {
2285         return insert(index, String.valueOf(value));
2286     }
2287 
2288     /**
2289      * Inserts the value into this builder.
2290      *
2291      * @param index the index to add at, must be valid
2292      * @param value the value to insert
2293      * @return this, to enable chaining
2294      * @throws IndexOutOfBoundsException if the index is invalid
2295      */
2296     public TextStringBuilder insert(final int index, final float value) {
2297         return insert(index, String.valueOf(value));
2298     }
2299 
2300     /**
2301      * Inserts the value into this builder.
2302      *
2303      * @param index the index to add at, must be valid
2304      * @param value the value to insert
2305      * @return this, to enable chaining
2306      * @throws IndexOutOfBoundsException if the index is invalid
2307      */
2308     public TextStringBuilder insert(final int index, final int value) {
2309         return insert(index, String.valueOf(value));
2310     }
2311 
2312     /**
2313      * Inserts the value into this builder.
2314      *
2315      * @param index the index to add at, must be valid
2316      * @param value the value to insert
2317      * @return this, to enable chaining
2318      * @throws IndexOutOfBoundsException if the index is invalid
2319      */
2320     public TextStringBuilder insert(final int index, final long value) {
2321         return insert(index, String.valueOf(value));
2322     }
2323 
2324     /**
2325      * Inserts the string representation of an object into this builder. Inserting null will use the stored null text
2326      * value.
2327      *
2328      * @param index the index to add at, must be valid
2329      * @param obj the object to insert
2330      * @return this, to enable chaining
2331      * @throws IndexOutOfBoundsException if the index is invalid
2332      */
2333     public TextStringBuilder insert(final int index, final Object obj) {
2334         if (obj == null) {
2335             return insert(index, nullText);
2336         }
2337         return insert(index, obj.toString());
2338     }
2339 
2340     /**
2341      * Inserts the string into this builder. Inserting null will use the stored null text value.
2342      *
2343      * @param index the index to add at, must be valid
2344      * @param str the string to insert
2345      * @return this, to enable chaining
2346      * @throws IndexOutOfBoundsException if the index is invalid
2347      */
2348     public TextStringBuilder insert(final int index, String str) {
2349         validateIndex(index);
2350         if (str == null) {
2351             str = nullText;
2352         }
2353         if (str != null) {
2354             final int strLen = str.length();
2355             if (strLen > 0) {
2356                 final int newSize = size + strLen;
2357                 ensureCapacityInternal(newSize);
2358                 System.arraycopy(buffer, index, buffer, index + strLen, size - index);
2359                 size = newSize;
2360                 str.getChars(0, strLen, buffer, index);
2361             }
2362         }
2363         return this;
2364     }
2365 
2366     /**
2367      * Checks is the string builder is empty (convenience Collections API style method).
2368      * <p>
2369      * This method is the same as checking {@link #length()} and is provided to match the API of Collections.
2370      * </p>
2371      *
2372      * @return {@code true} if the size is {@code 0}.
2373      */
2374     public boolean isEmpty() {
2375         return size == 0;
2376     }
2377 
2378     /**
2379      * Checks is the string builder is not empty.
2380      * <p>
2381      * This method is the same as checking {@link #length()}.
2382      * </p>
2383      *
2384      * @return {@code true} if the size is not {@code 0}.
2385      * @since 1.9
2386      */
2387     public boolean isNotEmpty() {
2388         return size != 0;
2389     }
2390 
2391     /**
2392      * Gets whether the internal buffer has been reallocated.
2393      *
2394      * @return Whether the internal buffer has been reallocated.
2395      * @since 1.9
2396      */
2397     public boolean isReallocated() {
2398         return reallocations > 0;
2399     }
2400 
2401     /**
2402      * Searches the string builder to find the last reference to the specified char.
2403      *
2404      * @param ch the character to find
2405      * @return The last index of the character, or -1 if not found
2406      */
2407     public int lastIndexOf(final char ch) {
2408         return lastIndexOf(ch, size - 1);
2409     }
2410 
2411     /**
2412      * Searches the string builder to find the last reference to the specified char.
2413      *
2414      * @param ch the character to find
2415      * @param startIndex the index to start at, invalid index rounded to edge
2416      * @return The last index of the character, or -1 if not found
2417      */
2418     public int lastIndexOf(final char ch, int startIndex) {
2419         startIndex = startIndex >= size ? size - 1 : startIndex;
2420         if (startIndex < 0) {
2421             return StringUtils.INDEX_NOT_FOUND;
2422         }
2423         for (int i = startIndex; i >= 0; i--) {
2424             if (buffer[i] == ch) {
2425                 return i;
2426             }
2427         }
2428         return StringUtils.INDEX_NOT_FOUND;
2429     }
2430 
2431     /**
2432      * Searches the string builder to find the last reference to the specified string.
2433      * <p>
2434      * Note that a null input string will return -1, whereas the JDK throws an exception.
2435      * </p>
2436      *
2437      * @param str the string to find, null returns -1
2438      * @return The last index of the string, or -1 if not found
2439      */
2440     public int lastIndexOf(final String str) {
2441         return lastIndexOf(str, size - 1);
2442     }
2443 
2444     /**
2445      * Searches the string builder to find the last reference to the specified string starting searching from the given
2446      * index.
2447      * <p>
2448      * Note that a null input string will return -1, whereas the JDK throws an exception.
2449      * </p>
2450      *
2451      * @param str the string to find, null returns -1
2452      * @param startIndex the index to start at, invalid index rounded to edge
2453      * @return The last index of the string, or -1 if not found
2454      */
2455     public int lastIndexOf(final String str, int startIndex) {
2456         startIndex = startIndex >= size ? size - 1 : startIndex;
2457         if (str == null || startIndex < 0) {
2458             return StringUtils.INDEX_NOT_FOUND;
2459         }
2460         final int strLen = str.length();
2461         if (strLen == 0) {
2462             return startIndex;
2463         }
2464         if (strLen > size) {
2465             return StringUtils.INDEX_NOT_FOUND;
2466         }
2467         if (strLen == 1) {
2468             return lastIndexOf(str.charAt(0), startIndex);
2469         }
2470         for (int i = startIndex - strLen + 1; i >= 0; i--) {
2471             boolean found = true;
2472             for (int j = 0; j < strLen && found; j++) {
2473                 found = str.charAt(j) == buffer[i + j];
2474             }
2475             if (found) {
2476                 return i;
2477             }
2478         }
2479         return StringUtils.INDEX_NOT_FOUND;
2480     }
2481 
2482     /**
2483      * Searches the string builder using the matcher to find the last match.
2484      * <p>
2485      * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the
2486      * character 'a' followed by a number.
2487      * </p>
2488      *
2489      * @param matcher the matcher to use, null returns -1
2490      * @return The last index matched, or -1 if not found
2491      */
2492     public int lastIndexOf(final StringMatcher matcher) {
2493         return lastIndexOf(matcher, size);
2494     }
2495 
2496     /**
2497      * Searches the string builder using the matcher to find the last match searching from the given index.
2498      * <p>
2499      * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the
2500      * character 'a' followed by a number.
2501      * </p>
2502      *
2503      * @param matcher the matcher to use, null returns -1
2504      * @param startIndex the index to start at, invalid index rounded to edge
2505      * @return The last index matched, or -1 if not found
2506      */
2507     public int lastIndexOf(final StringMatcher matcher, int startIndex) {
2508         startIndex = startIndex >= size ? size - 1 : startIndex;
2509         if (matcher == null || startIndex < 0) {
2510             return StringUtils.INDEX_NOT_FOUND;
2511         }
2512         final char[] buf = buffer;
2513         final int endIndex = startIndex + 1;
2514         for (int i = startIndex; i >= 0; i--) {
2515             if (matcher.isMatch(buf, i, 0, endIndex) > 0) {
2516                 return i;
2517             }
2518         }
2519         return StringUtils.INDEX_NOT_FOUND;
2520     }
2521 
2522     /**
2523      * Extracts the leftmost characters from the string builder without throwing an exception.
2524      * <p>
2525      * This method extracts the left {@code length} characters from the builder. If this many characters are not
2526      * available, the whole builder is returned. Thus the returned string may be shorter than the length requested.
2527      * </p>
2528      *
2529      * @param length the number of characters to extract, negative returns empty string
2530      * @return The new string
2531      */
2532     public String leftString(final int length) {
2533         if (length <= 0) {
2534             return StringUtils.EMPTY;
2535         }
2536         if (length >= size) {
2537             return new String(buffer, 0, size);
2538         }
2539         return new String(buffer, 0, length);
2540     }
2541 
2542     /**
2543      * Gets the length of the string builder.
2544      *
2545      * @return The length
2546      */
2547     @Override
2548     public int length() {
2549         return size;
2550     }
2551 
2552     /**
2553      * Extracts some characters from the middle of the string builder without throwing an exception.
2554      * <p>
2555      * This method extracts {@code length} characters from the builder at the specified index. If the index is negative
2556      * it is treated as zero. If the index is greater than the builder size, it is treated as the builder size. If the
2557      * length is negative, the empty string is returned. If insufficient characters are available in the builder, as
2558      * much as possible is returned. Thus the returned string may be shorter than the length requested.
2559      * </p>
2560      *
2561      * @param index the index to start at, negative means zero
2562      * @param length the number of characters to extract, negative returns empty string
2563      * @return The new string
2564      */
2565     public String midString(int index, final int length) {
2566         if (index < 0) {
2567             index = 0;
2568         }
2569         if (length <= 0 || index >= size) {
2570             return StringUtils.EMPTY;
2571         }
2572         if (size <= index + length) {
2573             return new String(buffer, index, size - index);
2574         }
2575         return new String(buffer, index, length);
2576     }
2577 
2578     /**
2579      * Minimizes the capacity to the actual length of the string.
2580      *
2581      * @return this, to enable chaining
2582      */
2583     public TextStringBuilder minimizeCapacity() {
2584         if (buffer.length > size) {
2585             reallocate(size);
2586         }
2587         return this;
2588     }
2589 
2590     /**
2591      * If possible, reads chars from the provided {@link CharBuffer} directly into underlying character buffer without
2592      * making extra copies.
2593      *
2594      * @param charBuffer CharBuffer to read.
2595      * @return The number of characters read.
2596      * @see #appendTo(Appendable)
2597      * @since 1.9
2598      */
2599     public int readFrom(final CharBuffer charBuffer) {
2600         final int oldSize = size;
2601         final int remaining = charBuffer.remaining();
2602         ensureCapacityInternal(size + remaining);
2603         charBuffer.get(buffer, size, remaining);
2604         size += remaining;
2605         return size - oldSize;
2606     }
2607 
2608     /**
2609      * If possible, reads all chars from the provided {@link Readable} directly into underlying character buffer without
2610      * making extra copies.
2611      *
2612      * @param readable object to read from
2613      * @return The number of characters read
2614      * @throws IOException if an I/O error occurs.
2615      * @see #appendTo(Appendable)
2616      */
2617     public int readFrom(final Readable readable) throws IOException {
2618         if (readable instanceof Reader) {
2619             return readFrom((Reader) readable);
2620         }
2621         if (readable instanceof CharBuffer) {
2622             return readFrom((CharBuffer) readable);
2623         }
2624         final int oldSize = size;
2625         while (true) {
2626             ensureCapacityInternal(size + 1);
2627             final CharBuffer buf = CharBuffer.wrap(buffer, size, buffer.length - size);
2628             final int read = readable.read(buf);
2629             if (read == EOS) {
2630                 break;
2631             }
2632             size += read;
2633         }
2634         return size - oldSize;
2635     }
2636 
2637     /**
2638      * If possible, reads all chars from the provided {@link Reader} directly into underlying character buffer without
2639      * making extra copies.
2640      *
2641      * @param reader Reader to read.
2642      * @return The number of characters read or -1 if we reached the end of stream.
2643      * @throws IOException if an I/O error occurs.
2644      * @see #appendTo(Appendable)
2645      * @since 1.9
2646      */
2647     public int readFrom(final Reader reader) throws IOException {
2648         final int oldSize = size;
2649         ensureCapacityInternal(size + 1);
2650         int readCount = reader.read(buffer, size, buffer.length - size);
2651         if (readCount == EOS) {
2652             return EOS;
2653         }
2654         do {
2655             size += readCount;
2656             ensureCapacityInternal(size + 1);
2657             readCount = reader.read(buffer, size, buffer.length - size);
2658         } while (readCount != EOS);
2659         return size - oldSize;
2660     }
2661 
2662     /**
2663      * If possible, reads {@code count} chars from the provided {@link Reader} directly into underlying character buffer
2664      * without making extra copies.
2665      *
2666      * @param reader Reader to read.
2667      * @param count The maximum characters to read, a value &lt;= 0 returns 0.
2668      * @return The number of characters read. If less than {@code count}, then we've reached the end-of-stream, or -1 if
2669      *         we reached the end of stream.
2670      * @throws IOException if an I/O error occurs.
2671      * @see #appendTo(Appendable)
2672      * @since 1.9
2673      */
2674     public int readFrom(final Reader reader, final int count) throws IOException {
2675         if (count <= 0) {
2676             return 0;
2677         }
2678         final int oldSize = size;
2679         ensureCapacityInternal(size + count);
2680         int target = count;
2681         int readCount = reader.read(buffer, size, target);
2682         if (readCount == EOS) {
2683             return EOS;
2684         }
2685         do {
2686             target -= readCount;
2687             size += readCount;
2688             readCount = reader.read(buffer, size, target);
2689         } while (target > 0 && readCount != EOS);
2690         return size - oldSize;
2691     }
2692 
2693     /**
2694      * Reallocates the buffer to the new length.
2695      *
2696      * @param newLength the length of the copy to be returned
2697      */
2698     private void reallocate(final int newLength) {
2699         this.buffer = Arrays.copyOf(buffer, newLength);
2700         this.reallocations++;
2701     }
2702 
2703     /**
2704      * Replaces a portion of the string builder with another string. The length of the inserted string does not have to
2705      * match the removed length.
2706      *
2707      * @param startIndex the start index, inclusive, must be valid
2708      * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string
2709      * @param replaceStr the string to replace with, null means delete range
2710      * @return this, to enable chaining
2711      * @throws IndexOutOfBoundsException if the index is invalid
2712      */
2713     public TextStringBuilder replace(final int startIndex, int endIndex, final String replaceStr) {
2714         endIndex = validateRange(startIndex, endIndex);
2715         final int insertLen = replaceStr == null ? 0 : replaceStr.length();
2716         replaceImpl(startIndex, endIndex, endIndex - startIndex, replaceStr, insertLen);
2717         return this;
2718     }
2719 
2720     /**
2721      * Advanced search and replaces within the builder using a matcher.
2722      * <p>
2723      * Matchers can be used to perform advanced behavior. For example you could write a matcher to delete all
2724      * occurrences where the character 'a' is followed by a number.
2725      * </p>
2726      *
2727      * @param matcher the matcher to use to find the deletion, null causes no action
2728      * @param replaceStr the string to replace the match with, null is a delete
2729      * @param startIndex the start index, inclusive, must be valid
2730      * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string
2731      * @param replaceCount the number of times to replace, -1 for replace all
2732      * @return this, to enable chaining
2733      * @throws IndexOutOfBoundsException if start index is invalid
2734      */
2735     public TextStringBuilder replace(final StringMatcher matcher, final String replaceStr, final int startIndex,
2736         int endIndex, final int replaceCount) {
2737         endIndex = validateRange(startIndex, endIndex);
2738         return replaceImpl(matcher, replaceStr, startIndex, endIndex, replaceCount);
2739     }
2740 
2741     /**
2742      * Replaces the search character with the replace character throughout the builder.
2743      *
2744      * @param search the search character
2745      * @param replace the replace character
2746      * @return this, to enable chaining
2747      */
2748     public TextStringBuilder replaceAll(final char search, final char replace) {
2749         if (search != replace) {
2750             for (int i = 0; i < size; i++) {
2751                 if (buffer[i] == search) {
2752                     buffer[i] = replace;
2753                 }
2754             }
2755         }
2756         return this;
2757     }
2758 
2759     /**
2760      * Replaces the search string with the replace string throughout the builder.
2761      *
2762      * @param searchStr the search string, null causes no action to occur
2763      * @param replaceStr the replace string, null is equivalent to an empty string
2764      * @return this, to enable chaining
2765      */
2766     public TextStringBuilder replaceAll(final String searchStr, final String replaceStr) {
2767         final int searchLen = searchStr == null ? 0 : searchStr.length();
2768         if (searchLen > 0) {
2769             final int replaceLen = replaceStr == null ? 0 : replaceStr.length();
2770             int index = indexOf(searchStr, 0);
2771             while (index >= 0) {
2772                 replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen);
2773                 index = indexOf(searchStr, index + replaceLen);
2774             }
2775         }
2776         return this;
2777     }
2778 
2779     /**
2780      * Replaces all matches within the builder with the replace string.
2781      * <p>
2782      * Matchers can be used to perform advanced replace behavior. For example you could write a matcher to replace all
2783      * occurrences where the character 'a' is followed by a number.
2784      * </p>
2785      *
2786      * @param matcher the matcher to use to find the deletion, null causes no action
2787      * @param replaceStr the replace string, null is equivalent to an empty string
2788      * @return this, to enable chaining
2789      */
2790     public TextStringBuilder replaceAll(final StringMatcher matcher, final String replaceStr) {
2791         return replace(matcher, replaceStr, 0, size, -1);
2792     }
2793 
2794     /**
2795      * Replaces the first instance of the search character with the replace character in the builder.
2796      *
2797      * @param search the search character
2798      * @param replace the replace character
2799      * @return this, to enable chaining
2800      */
2801     public TextStringBuilder replaceFirst(final char search, final char replace) {
2802         if (search != replace) {
2803             for (int i = 0; i < size; i++) {
2804                 if (buffer[i] == search) {
2805                     buffer[i] = replace;
2806                     break;
2807                 }
2808             }
2809         }
2810         return this;
2811     }
2812 
2813     /**
2814      * Replaces the first instance of the search string with the replace string.
2815      *
2816      * @param searchStr the search string, null causes no action to occur
2817      * @param replaceStr the replace string, null is equivalent to an empty string
2818      * @return this, to enable chaining
2819      */
2820     public TextStringBuilder replaceFirst(final String searchStr, final String replaceStr) {
2821         final int searchLen = searchStr == null ? 0 : searchStr.length();
2822         if (searchLen > 0) {
2823             final int index = indexOf(searchStr, 0);
2824             if (index >= 0) {
2825                 final int replaceLen = replaceStr == null ? 0 : replaceStr.length();
2826                 replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen);
2827             }
2828         }
2829         return this;
2830     }
2831 
2832     /**
2833      * Replaces the first match within the builder with the replace string.
2834      * <p>
2835      * Matchers can be used to perform advanced replace behavior. For example you could write a matcher to replace where
2836      * the character 'a' is followed by a number.
2837      * </p>
2838      *
2839      * @param matcher the matcher to use to find the deletion, null causes no action
2840      * @param replaceStr the replace string, null is equivalent to an empty string
2841      * @return this, to enable chaining
2842      */
2843     public TextStringBuilder replaceFirst(final StringMatcher matcher, final String replaceStr) {
2844         return replace(matcher, replaceStr, 0, size, 1);
2845     }
2846 
2847     /**
2848      * Internal method to delete a range without validation.
2849      *
2850      * @param startIndex the start index, must be valid
2851      * @param endIndex the end index (exclusive), must be valid
2852      * @param removeLen the length to remove (endIndex - startIndex), must be valid
2853      * @param insertStr the string to replace with, null means delete range
2854      * @param insertLen the length of the insert string, must be valid
2855      * @throws IndexOutOfBoundsException if any index is invalid
2856      */
2857     private void replaceImpl(final int startIndex, final int endIndex, final int removeLen, final String insertStr,
2858         final int insertLen) {
2859         final int newSize = size - removeLen + insertLen;
2860         if (insertLen != removeLen) {
2861             ensureCapacityInternal(newSize);
2862             System.arraycopy(buffer, endIndex, buffer, startIndex + insertLen, size - endIndex);
2863             size = newSize;
2864         }
2865         if (insertLen > 0) {
2866             insertStr.getChars(0, insertLen, buffer, startIndex);
2867         }
2868     }
2869 
2870     /**
2871      * Replaces within the builder using a matcher.
2872      * <p>
2873      * Matchers can be used to perform advanced behavior. For example you could write a matcher to delete all
2874      * occurrences where the character 'a' is followed by a number.
2875      * </p>
2876      *
2877      * @param matcher the matcher to use to find the deletion, null causes no action
2878      * @param replaceStr the string to replace the match with, null is a delete
2879      * @param from the start index, must be valid
2880      * @param to the end index (exclusive), must be valid
2881      * @param replaceCount the number of times to replace, -1 for replace all
2882      * @return this, to enable chaining
2883      * @throws IndexOutOfBoundsException if any index is invalid
2884      */
2885     private TextStringBuilder replaceImpl(final StringMatcher matcher, final String replaceStr, final int from, int to,
2886         int replaceCount) {
2887         if (matcher == null || size == 0) {
2888             return this;
2889         }
2890         final int replaceLen = replaceStr == null ? 0 : replaceStr.length();
2891         for (int i = from; i < to && replaceCount != 0; i++) {
2892             final char[] buf = buffer;
2893             final int removeLen = matcher.isMatch(buf, i, from, to);
2894             if (removeLen > 0) {
2895                 replaceImpl(i, i + removeLen, removeLen, replaceStr, replaceLen);
2896                 to = to - removeLen + replaceLen;
2897                 i = i + replaceLen - 1;
2898                 if (replaceCount > 0) {
2899                     replaceCount--;
2900                 }
2901             }
2902         }
2903         return this;
2904     }
2905 
2906     /**
2907      * Resizes the buffer to at least the size specified.
2908      *
2909      * @param minCapacity the minimum required capacity
2910      * @throws OutOfMemoryError if the {@code minCapacity} is negative
2911      */
2912     private void resizeBuffer(final int minCapacity) {
2913         // Overflow-conscious code treats the min and new capacity as unsigned.
2914         final int oldCapacity = buffer.length;
2915         int newCapacity = oldCapacity * 2;
2916         if (Integer.compareUnsigned(newCapacity, minCapacity) < 0) {
2917             newCapacity = minCapacity;
2918         }
2919         if (Integer.compareUnsigned(newCapacity, MAX_BUFFER_SIZE) > 0) {
2920             newCapacity = createPositiveCapacity(minCapacity);
2921         }
2922         reallocate(newCapacity);
2923     }
2924 
2925     /**
2926      * Reverses the string builder placing each character in the opposite index.
2927      *
2928      * @return this, to enable chaining
2929      */
2930     public TextStringBuilder reverse() {
2931         if (size == 0) {
2932             return this;
2933         }
2934 
2935         final int half = size / 2;
2936         final char[] buf = buffer;
2937         for (int leftIdx = 0, rightIdx = size - 1; leftIdx < half; leftIdx++, rightIdx--) {
2938             final char swap = buf[leftIdx];
2939             buf[leftIdx] = buf[rightIdx];
2940             buf[rightIdx] = swap;
2941         }
2942         return this;
2943     }
2944 
2945     /**
2946      * Extracts the rightmost characters from the string builder without throwing an exception.
2947      * <p>
2948      * This method extracts the right {@code length} characters from the builder. If this many characters are not
2949      * available, the whole builder is returned. Thus the returned string may be shorter than the length requested.
2950      * </p>
2951      *
2952      * @param length the number of characters to extract, negative returns empty string
2953      * @return The new string
2954      */
2955     public String rightString(final int length) {
2956         if (length <= 0) {
2957             return StringUtils.EMPTY;
2958         }
2959         if (length >= size) {
2960             return new String(buffer, 0, size);
2961         }
2962         return new String(buffer, size - length, length);
2963     }
2964 
2965     /**
2966      * Clears and sets this builder to the given value.
2967      *
2968      * @see #charAt(int)
2969      * @see #deleteCharAt(int)
2970      * @param str the new value.
2971      * @return this, to enable chaining
2972      * @since 1.9
2973      */
2974     public TextStringBuilder set(final CharSequence str) {
2975         clear();
2976         append(str);
2977         return this;
2978     }
2979 
2980     /**
2981      * Sets the character at the specified index.
2982      *
2983      * @see #charAt(int)
2984      * @see #deleteCharAt(int)
2985      * @param index the index to set
2986      * @param ch the new character
2987      * @return this, to enable chaining
2988      * @throws IndexOutOfBoundsException if the index is invalid
2989      */
2990     public TextStringBuilder setCharAt(final int index, final char ch) {
2991         validateIndex(index);
2992         buffer[index] = ch;
2993         return this;
2994     }
2995 
2996     /**
2997      * Updates the length of the builder by either dropping the last characters or adding filler of Unicode zero.
2998      *
2999      * @param length the length to set to, must be zero or positive
3000      * @return this, to enable chaining
3001      * @throws IndexOutOfBoundsException if the length is negative
3002      */
3003     public TextStringBuilder setLength(final int length) {
3004         if (length < 0) {
3005             throw new StringIndexOutOfBoundsException(length);
3006         }
3007         if (length < size) {
3008             size = length;
3009         } else if (length > size) {
3010             ensureCapacityInternal(length);
3011             final int oldEnd = size;
3012             size = length;
3013             Arrays.fill(buffer, oldEnd, length, '\0');
3014         }
3015         return this;
3016     }
3017 
3018     /**
3019      * Sets the text to be appended when {@link #appendNewLine() new line} is called.
3020      *
3021      * @param newLine the new line text, {@code null} means use the system default from {@link System#lineSeparator()}.
3022      * @return this instance.
3023      */
3024     public TextStringBuilder setNewLineText(final String newLine) {
3025         this.newLine = newLine;
3026         return this;
3027     }
3028 
3029     /**
3030      * Sets the text to be appended when null is added.
3031      *
3032      * @param nullText the null text, null means no append
3033      * @return this, to enable chaining
3034      */
3035     public TextStringBuilder setNullText(String nullText) {
3036         if (nullText != null && nullText.isEmpty()) {
3037             nullText = null;
3038         }
3039         this.nullText = nullText;
3040         return this;
3041     }
3042 
3043     /**
3044      * Gets the length of the string builder.
3045      * <p>
3046      * This method is the same as {@link #length()} and is provided to match the API of Collections.
3047      * </p>
3048      *
3049      * @return The length
3050      */
3051     public int size() {
3052         return size;
3053     }
3054 
3055     /**
3056      * Checks whether this builder starts with the specified string.
3057      * <p>
3058      * Note that this method handles null input quietly, unlike String.
3059      * </p>
3060      *
3061      * @param str the string to search for, null returns false
3062      * @return true if the builder starts with the string
3063      */
3064     public boolean startsWith(final String str) {
3065         if (str == null) {
3066             return false;
3067         }
3068         final int len = str.length();
3069         if (len == 0) {
3070             return true;
3071         }
3072         if (len > size) {
3073             return false;
3074         }
3075         for (int i = 0; i < len; i++) {
3076             if (buffer[i] != str.charAt(i)) {
3077                 return false;
3078             }
3079         }
3080         return true;
3081     }
3082 
3083     /**
3084      * {@inheritDoc}
3085      */
3086     @Override
3087     public CharSequence subSequence(final int startIndex, final int endIndex) {
3088         if (startIndex < 0) {
3089             throw new StringIndexOutOfBoundsException(startIndex);
3090         }
3091         if (endIndex > size) {
3092             throw new StringIndexOutOfBoundsException(endIndex);
3093         }
3094         if (startIndex > endIndex) {
3095             throw new StringIndexOutOfBoundsException(endIndex - startIndex);
3096         }
3097         return substring(startIndex, endIndex);
3098     }
3099 
3100     /**
3101      * Extracts a portion of this string builder as a string.
3102      *
3103      * @param start the start index, inclusive, must be valid
3104      * @return The new string
3105      * @throws IndexOutOfBoundsException if the index is invalid
3106      */
3107     public String substring(final int start) {
3108         return substring(start, size);
3109     }
3110 
3111     /**
3112      * Extracts a portion of this string builder as a string.
3113      * <p>
3114      * Note: This method treats an endIndex greater than the length of the builder as equal to the length of the
3115      * builder, and continues without error, unlike StringBuffer or String.
3116      * </p>
3117      *
3118      * @param startIndex the start index, inclusive, must be valid
3119      * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string
3120      * @return The new string
3121      * @throws IndexOutOfBoundsException if the index is invalid
3122      */
3123     public String substring(final int startIndex, int endIndex) {
3124         endIndex = validateRange(startIndex, endIndex);
3125         return new String(buffer, startIndex, endIndex - startIndex);
3126     }
3127 
3128     /**
3129      * Copies the builder's character array into a new character array.
3130      *
3131      * @return a new array that represents the contents of the builder
3132      */
3133     public char[] toCharArray() {
3134         return size == 0 ? ArrayUtils.EMPTY_CHAR_ARRAY : Arrays.copyOf(buffer, size);
3135     }
3136 
3137     /**
3138      * Copies part of the builder's character array into a new character array.
3139      *
3140      * @param startIndex the start index, inclusive, must be valid
3141      * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string
3142      * @return a new array that holds part of the contents of the builder
3143      * @throws IndexOutOfBoundsException if startIndex is invalid, or if endIndex is invalid (but endIndex greater than
3144      *         size is valid)
3145      */
3146     public char[] toCharArray(final int startIndex, int endIndex) {
3147         endIndex = validateRange(startIndex, endIndex);
3148         final int len = endIndex - startIndex;
3149         return len == 0 ? ArrayUtils.EMPTY_CHAR_ARRAY : Arrays.copyOfRange(buffer, startIndex, endIndex);
3150     }
3151 
3152     /**
3153      * Gets a String version of the string builder, creating a new instance each time the method is called.
3154      * <p>
3155      * Note that unlike StringBuffer, the string version returned is independent of the string builder.
3156      * </p>
3157      *
3158      * @return The builder as a String
3159      */
3160     @Override
3161     public String toString() {
3162         return new String(buffer, 0, size);
3163     }
3164 
3165     /**
3166      * Gets a StringBuffer version of the string builder, creating a new instance each time the method is called.
3167      *
3168      * @return The builder as a StringBuffer
3169      */
3170     public StringBuffer toStringBuffer() {
3171         return new StringBuffer(size).append(buffer, 0, size);
3172     }
3173 
3174     /**
3175      * Gets a StringBuilder version of the string builder, creating a new instance each time the method is called.
3176      *
3177      * @return The builder as a StringBuilder
3178      */
3179     public StringBuilder toStringBuilder() {
3180         return new StringBuilder(size).append(buffer, 0, size);
3181     }
3182 
3183     /**
3184      * Trims the builder by removing characters less than or equal to a space from the beginning and end.
3185      *
3186      * @return this, to enable chaining
3187      */
3188     public TextStringBuilder trim() {
3189         if (size == 0) {
3190             return this;
3191         }
3192         int len = size;
3193         final char[] buf = buffer;
3194         int pos = 0;
3195         while (pos < len && buf[pos] <= SPACE) {
3196             pos++;
3197         }
3198         while (pos < len && buf[len - 1] <= SPACE) {
3199             len--;
3200         }
3201         if (len < size) {
3202             delete(len, size);
3203         }
3204         if (pos > 0) {
3205             delete(0, pos);
3206         }
3207         return this;
3208     }
3209 
3210     /**
3211      * Validates that an index is in the range {@code 0 <= index <= size}.
3212      *
3213      * @param index the index to test.
3214      * @throws IndexOutOfBoundsException Thrown when the index is not the range {@code 0 <= index <= size}.
3215      */
3216     protected void validateIndex(final int index) {
3217         if (index < 0 || index >= size) {
3218             throw new StringIndexOutOfBoundsException(index);
3219         }
3220     }
3221 
3222     /**
3223      * Validates parameters defining a range of the builder.
3224      *
3225      * @param startIndex the start index, inclusive, must be valid
3226      * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string
3227      * @return A valid end index.
3228      * @throws StringIndexOutOfBoundsException if the index is invalid
3229      */
3230     protected int validateRange(final int startIndex, int endIndex) {
3231         if (startIndex < 0) {
3232             throw new StringIndexOutOfBoundsException(startIndex);
3233         }
3234         if (endIndex > size) {
3235             endIndex = size;
3236         }
3237         if (startIndex > endIndex) {
3238             throw new StringIndexOutOfBoundsException("end < start");
3239         }
3240         return endIndex;
3241     }
3242 
3243 }