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