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