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