View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.text;
18  
19  import java.io.IOException;
20  import java.io.Reader;
21  import java.io.Serializable;
22  import java.io.Writer;
23  import java.nio.CharBuffer;
24  import java.util.Arrays;
25  import java.util.Iterator;
26  import java.util.List;
27  import java.util.Objects;
28  
29  import org.apache.commons.lang3.ArrayUtils;
30  import org.apache.commons.lang3.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(startIndex, 0);
1950         if (str == null || startIndex >= size) {
1951             return -1;
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 -1;
1962         }
1963         final char[] thisBuf = buffer;
1964         final int len = size - strLen + 1;
1965         outer: for (int i = startIndex; i < len; i++) {
1966             for (int j = 0; j < strLen; j++) {
1967                 if (str.charAt(j) != thisBuf[i + j]) {
1968                     continue outer;
1969                 }
1970             }
1971             return i;
1972         }
1973         return -1;
1974     }
1975 
1976     /**
1977      * Searches the string builder using the matcher to find the first match.
1978      * <p>
1979      * 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.
1980      * </p>
1981      *
1982      * @param matcher the matcher to use, null returns -1
1983      * @return The first index matched, or -1 if not found
1984      */
1985     public int indexOf(final StrMatcher matcher) {
1986         return indexOf(matcher, 0);
1987     }
1988 
1989     /**
1990      * Searches the string builder using the matcher to find the first match searching from the given index.
1991      * <p>
1992      * 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.
1993      * </p>
1994      *
1995      * @param matcher    the matcher to use, null returns -1
1996      * @param startIndex the index to start at, invalid index rounded to edge
1997      * @return The first index matched, or -1 if not found
1998      */
1999     public int indexOf(final StrMatcher matcher, int startIndex) {
2000         startIndex = Math.max(startIndex, 0);
2001         if (matcher == null || startIndex >= size) {
2002             return -1;
2003         }
2004         final int len = size;
2005         final char[] buf = buffer;
2006         for (int i = startIndex; i < len; i++) {
2007             if (matcher.isMatch(buf, i, startIndex, len) > 0) {
2008                 return i;
2009             }
2010         }
2011         return -1;
2012     }
2013 
2014     /**
2015      * Inserts the value into this builder.
2016      *
2017      * @param index the index to add at, must be valid
2018      * @param value the value to insert
2019      * @return {@code this} instance.
2020      * @throws IndexOutOfBoundsException if the index is invalid
2021      */
2022     public StrBuilder insert(int index, final boolean value) {
2023         validateIndex(index);
2024         if (value) {
2025             ensureCapacity(size + 4);
2026             System.arraycopy(buffer, index, buffer, index + 4, size - index);
2027             buffer[index++] = 't';
2028             buffer[index++] = 'r';
2029             buffer[index++] = 'u';
2030             buffer[index] = 'e';
2031             size += 4;
2032         } else {
2033             ensureCapacity(size + 5);
2034             System.arraycopy(buffer, index, buffer, index + 5, size - index);
2035             buffer[index++] = 'f';
2036             buffer[index++] = 'a';
2037             buffer[index++] = 'l';
2038             buffer[index++] = 's';
2039             buffer[index] = 'e';
2040             size += 5;
2041         }
2042         return this;
2043     }
2044 
2045     /**
2046      * Inserts the value into this builder.
2047      *
2048      * @param index the index to add at, must be valid
2049      * @param value the value to insert
2050      * @return {@code this} instance.
2051      * @throws IndexOutOfBoundsException if the index is invalid
2052      */
2053     public StrBuilder insert(final int index, final char value) {
2054         validateIndex(index);
2055         ensureCapacity(size + 1);
2056         System.arraycopy(buffer, index, buffer, index + 1, size - index);
2057         buffer[index] = value;
2058         size++;
2059         return this;
2060     }
2061 
2062     /**
2063      * Inserts the character array into this builder. Inserting null will use the stored null text value.
2064      *
2065      * @param index the index to add at, must be valid
2066      * @param chars the char array to insert
2067      * @return {@code this} instance.
2068      * @throws IndexOutOfBoundsException if the index is invalid
2069      */
2070     public StrBuilder insert(final int index, final char[] chars) {
2071         validateIndex(index);
2072         if (chars == null) {
2073             return insert(index, nullText);
2074         }
2075         final int len = chars.length;
2076         if (len > 0) {
2077             ensureCapacity(size + len);
2078             System.arraycopy(buffer, index, buffer, index + len, size - index);
2079             System.arraycopy(chars, 0, buffer, index, len);
2080             size += len;
2081         }
2082         return this;
2083     }
2084 
2085     /**
2086      * Inserts part of the character array into this builder. Inserting null will use the stored null text value.
2087      *
2088      * @param index  the index to add at, must be valid
2089      * @param chars  the char array to insert
2090      * @param offset the offset into the character array to start at, must be valid
2091      * @param length the length of the character array part to copy, must be positive
2092      * @return {@code this} instance.
2093      * @throws IndexOutOfBoundsException if any index is invalid
2094      */
2095     public StrBuilder insert(final int index, final char[] chars, final int offset, final int length) {
2096         validateIndex(index);
2097         if (chars == null) {
2098             return insert(index, nullText);
2099         }
2100         if (offset < 0 || offset > chars.length) {
2101             throw new StringIndexOutOfBoundsException("Invalid offset: " + offset);
2102         }
2103         if (length < 0 || offset + length > chars.length) {
2104             throw new StringIndexOutOfBoundsException("Invalid length: " + length);
2105         }
2106         if (length > 0) {
2107             ensureCapacity(size + length);
2108             System.arraycopy(buffer, index, buffer, index + length, size - index);
2109             System.arraycopy(chars, offset, buffer, index, length);
2110             size += length;
2111         }
2112         return this;
2113     }
2114 
2115     /**
2116      * Inserts the value into this builder.
2117      *
2118      * @param index the index to add at, must be valid
2119      * @param value the value to insert
2120      * @return {@code this} instance.
2121      * @throws IndexOutOfBoundsException if the index is invalid
2122      */
2123     public StrBuilder insert(final int index, final double value) {
2124         return insert(index, String.valueOf(value));
2125     }
2126 
2127     /**
2128      * Inserts the value into this builder.
2129      *
2130      * @param index the index to add at, must be valid
2131      * @param value the value to insert
2132      * @return {@code this} instance.
2133      * @throws IndexOutOfBoundsException if the index is invalid
2134      */
2135     public StrBuilder insert(final int index, final float value) {
2136         return insert(index, String.valueOf(value));
2137     }
2138 
2139     /**
2140      * Inserts the value into this builder.
2141      *
2142      * @param index the index to add at, must be valid
2143      * @param value the value to insert
2144      * @return {@code this} instance.
2145      * @throws IndexOutOfBoundsException if the index is invalid
2146      */
2147     public StrBuilder insert(final int index, final int value) {
2148         return insert(index, String.valueOf(value));
2149     }
2150 
2151     /**
2152      * Inserts the value into this builder.
2153      *
2154      * @param index the index to add at, must be valid
2155      * @param value the value to insert
2156      * @return {@code this} instance.
2157      * @throws IndexOutOfBoundsException if the index is invalid
2158      */
2159     public StrBuilder insert(final int index, final long value) {
2160         return insert(index, String.valueOf(value));
2161     }
2162 
2163     /**
2164      * Inserts the string representation of an object into this builder. Inserting null will use the stored null text value.
2165      *
2166      * @param index the index to add at, must be valid
2167      * @param obj   the object to insert
2168      * @return {@code this} instance.
2169      * @throws IndexOutOfBoundsException if the index is invalid
2170      */
2171     public StrBuilder insert(final int index, final Object obj) {
2172         if (obj == null) {
2173             return insert(index, nullText);
2174         }
2175         return insert(index, obj.toString());
2176     }
2177 
2178     /**
2179      * Inserts the string into this builder. Inserting null will use the stored null text value.
2180      *
2181      * @param index the index to add at, must be valid
2182      * @param str   the string to insert
2183      * @return {@code this} instance.
2184      * @throws IndexOutOfBoundsException if the index is invalid
2185      */
2186     public StrBuilder insert(final int index, String str) {
2187         validateIndex(index);
2188         if (str == null) {
2189             str = nullText;
2190         }
2191         if (str != null) {
2192             final int strLen = str.length();
2193             if (strLen > 0) {
2194                 final int newSize = size + strLen;
2195                 ensureCapacity(newSize);
2196                 System.arraycopy(buffer, index, buffer, index + strLen, size - index);
2197                 size = newSize;
2198                 str.getChars(0, strLen, buffer, index);
2199             }
2200         }
2201         return this;
2202     }
2203 
2204     /**
2205      * Tests if the string builder is empty (convenience Collections API style method).
2206      * <p>
2207      * This method is the same as checking {@link #length()} and is provided to match the API of Collections.
2208      * </p>
2209      *
2210      * @return {@code true} if the size is {@code 0}.
2211      */
2212     public boolean isEmpty() {
2213         return size == 0;
2214     }
2215 
2216     /**
2217      * Tests if the string builder is not empty (convenience Collections API style method).
2218      * <p>
2219      * This method is the same as checking {@link #length()} and is provided to match the API of Collections.
2220      * </p>
2221      *
2222      * @return {@code true} if the size is greater than {@code 0}.
2223      * @since 1.10.0
2224      */
2225     public boolean isNotEmpty() {
2226         return size > 0;
2227     }
2228 
2229     /**
2230      * Searches the string builder to find the last reference to the specified char.
2231      *
2232      * @param ch the character to find
2233      * @return The last index of the character, or -1 if not found
2234      */
2235     public int lastIndexOf(final char ch) {
2236         return lastIndexOf(ch, size - 1);
2237     }
2238 
2239     /**
2240      * Searches the string builder to find the last reference to the specified char.
2241      *
2242      * @param ch         the character to find
2243      * @param startIndex the index to start at, invalid index rounded to edge
2244      * @return The last index of the character, or -1 if not found
2245      */
2246     public int lastIndexOf(final char ch, int startIndex) {
2247         startIndex = startIndex >= size ? size - 1 : startIndex;
2248         if (startIndex < 0) {
2249             return -1;
2250         }
2251         for (int i = startIndex; i >= 0; i--) {
2252             if (buffer[i] == ch) {
2253                 return i;
2254             }
2255         }
2256         return -1;
2257     }
2258 
2259     /**
2260      * Searches the string builder to find the last reference to the specified string.
2261      * <p>
2262      * Note that a null input string will return -1, whereas the JDK throws an exception.
2263      * </p>
2264      *
2265      * @param str the string to find, null returns -1
2266      * @return The last index of the string, or -1 if not found
2267      */
2268     public int lastIndexOf(final String str) {
2269         return lastIndexOf(str, size - 1);
2270     }
2271 
2272     /**
2273      * Searches the string builder to find the last reference to the specified string starting searching from the given index.
2274      * <p>
2275      * Note that a null input string will return -1, whereas the JDK throws an exception.
2276      * </p>
2277      *
2278      * @param str        the string to find, null returns -1
2279      * @param startIndex the index to start at, invalid index rounded to edge
2280      * @return The last index of the string, or -1 if not found
2281      */
2282     public int lastIndexOf(final String str, int startIndex) {
2283         startIndex = startIndex >= size ? size - 1 : startIndex;
2284         if (str == null || startIndex < 0) {
2285             return -1;
2286         }
2287         final int strLen = str.length();
2288         if (strLen > 0 && strLen <= size) {
2289             if (strLen == 1) {
2290                 return lastIndexOf(str.charAt(0), startIndex);
2291             }
2292 
2293             outer: for (int i = startIndex - strLen + 1; i >= 0; i--) {
2294                 for (int j = 0; j < strLen; j++) {
2295                     if (str.charAt(j) != buffer[i + j]) {
2296                         continue outer;
2297                     }
2298                 }
2299                 return i;
2300             }
2301 
2302         } else if (strLen == 0) {
2303             return startIndex;
2304         }
2305         return -1;
2306     }
2307 
2308     /**
2309      * Searches the string builder using the matcher to find the last match.
2310      * <p>
2311      * 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.
2312      * </p>
2313      *
2314      * @param matcher the matcher to use, null returns -1
2315      * @return The last index matched, or -1 if not found
2316      */
2317     public int lastIndexOf(final StrMatcher matcher) {
2318         return lastIndexOf(matcher, size);
2319     }
2320 
2321     /**
2322      * Searches the string builder using the matcher to find the last match searching from the given index.
2323      * <p>
2324      * 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.
2325      * </p>
2326      *
2327      * @param matcher    the matcher to use, null returns -1
2328      * @param startIndex the index to start at, invalid index rounded to edge
2329      * @return The last index matched, or -1 if not found
2330      */
2331     public int lastIndexOf(final StrMatcher matcher, int startIndex) {
2332         startIndex = startIndex >= size ? size - 1 : startIndex;
2333         if (matcher == null || startIndex < 0) {
2334             return -1;
2335         }
2336         final char[] buf = buffer;
2337         final int endIndex = startIndex + 1;
2338         for (int i = startIndex; i >= 0; i--) {
2339             if (matcher.isMatch(buf, i, 0, endIndex) > 0) {
2340                 return i;
2341             }
2342         }
2343         return -1;
2344     }
2345 
2346     /**
2347      * Extracts the leftmost characters from the string builder without throwing an exception.
2348      * <p>
2349      * This method extracts the left {@code length} characters from the builder. If this many characters are not available, the whole builder is returned. Thus
2350      * the returned string may be shorter than the length requested.
2351      * </p>
2352      *
2353      * @param length the number of characters to extract, negative returns empty string
2354      * @return The new string
2355      */
2356     public String leftString(final int length) {
2357         if (length <= 0) {
2358             return StringUtils.EMPTY;
2359         }
2360         if (length >= size) {
2361             return new String(buffer, 0, size);
2362         }
2363         return new String(buffer, 0, length);
2364     }
2365 
2366     /**
2367      * Gets the length of the string builder.
2368      *
2369      * @return The length
2370      */
2371     @Override
2372     public int length() {
2373         return size;
2374     }
2375 
2376     /**
2377      * Extracts some characters from the middle of the string builder without throwing an exception.
2378      * <p>
2379      * 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
2380      * 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
2381      * available in the builder, as much as possible is returned. Thus the returned string may be shorter than the length requested.
2382      * </p>
2383      *
2384      * @param index  the index to start at, negative means zero
2385      * @param length the number of characters to extract, negative returns empty string
2386      * @return The new string
2387      */
2388     public String midString(int index, final int length) {
2389         if (index < 0) {
2390             index = 0;
2391         }
2392         if (length <= 0 || index >= size) {
2393             return StringUtils.EMPTY;
2394         }
2395         if (size <= index + length) {
2396             return new String(buffer, index, size - index);
2397         }
2398         return new String(buffer, index, length);
2399     }
2400 
2401     /**
2402      * Minimizes the capacity to the actual length of the string.
2403      *
2404      * @return {@code this} instance.
2405      */
2406     public StrBuilder minimizeCapacity() {
2407         if (buffer.length > length()) {
2408             final char[] old = buffer;
2409             buffer = new char[length()];
2410             System.arraycopy(old, 0, buffer, 0, size);
2411         }
2412         return this;
2413     }
2414 
2415     /**
2416      * If possible, reads chars from the provided {@link Readable} directly into underlying character buffer without making extra copies.
2417      *
2418      * @param readable object to read from
2419      * @return The number of characters read
2420      * @throws IOException if an I/O error occurs.
2421      * @see #appendTo(Appendable)
2422      */
2423     public int readFrom(final Readable readable) throws IOException {
2424         final int oldSize = size;
2425         if (readable instanceof Reader) {
2426             final Reader r = (Reader) readable;
2427             ensureCapacity(size + 1);
2428             int read;
2429             while ((read = r.read(buffer, size, buffer.length - size)) != -1) {
2430                 size += read;
2431                 ensureCapacity(size + 1);
2432             }
2433         } else if (readable instanceof CharBuffer) {
2434             final CharBuffer cb = (CharBuffer) readable;
2435             final int remaining = cb.remaining();
2436             ensureCapacity(size + remaining);
2437             cb.get(buffer, size, remaining);
2438             size += remaining;
2439         } else {
2440             while (true) {
2441                 ensureCapacity(size + 1);
2442                 final CharBuffer buf = CharBuffer.wrap(buffer, size, buffer.length - size);
2443                 final int read = readable.read(buf);
2444                 if (read == -1) {
2445                     break;
2446                 }
2447                 size += read;
2448             }
2449         }
2450         return size - oldSize;
2451     }
2452 
2453     /**
2454      * Replaces a portion of the string builder with another string. The length of the inserted string does not have to match the removed length.
2455      *
2456      * @param startIndex the start index, inclusive, must be valid
2457      * @param endIndex   the end index, exclusive, must be valid except that if too large it is treated as end of string
2458      * @param replaceStr the string to replace with, null means delete range
2459      * @return {@code this} instance.
2460      * @throws IndexOutOfBoundsException if the index is invalid
2461      */
2462     public StrBuilder replace(final int startIndex, int endIndex, final String replaceStr) {
2463         endIndex = validateRange(startIndex, endIndex);
2464         final int insertLen = replaceStr == null ? 0 : replaceStr.length();
2465         replaceImpl(startIndex, endIndex, endIndex - startIndex, replaceStr, insertLen);
2466         return this;
2467     }
2468 
2469     /**
2470      * Advanced search and replaces within the builder using a matcher.
2471      * <p>
2472      * 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
2473      * a number.
2474      * </p>
2475      *
2476      * @param matcher      the matcher to use to find the deletion, null causes no action
2477      * @param replaceStr   the string to replace the match with, null is a delete
2478      * @param startIndex   the start index, inclusive, must be valid
2479      * @param endIndex     the end index, exclusive, must be valid except that if too large it is treated as end of string
2480      * @param replaceCount the number of times to replace, -1 for replace all
2481      * @return {@code this} instance.
2482      * @throws IndexOutOfBoundsException if start index is invalid
2483      */
2484     public StrBuilder replace(final StrMatcher matcher, final String replaceStr, final int startIndex, int endIndex, final int replaceCount) {
2485         endIndex = validateRange(startIndex, endIndex);
2486         return replaceImpl(matcher, replaceStr, startIndex, endIndex, replaceCount);
2487     }
2488 
2489     /**
2490      * Replaces the search character with the replace character throughout the builder.
2491      *
2492      * @param search  the search character
2493      * @param replace the replace character
2494      * @return {@code this} instance.
2495      */
2496     public StrBuilder replaceAll(final char search, final char replace) {
2497         if (search != replace) {
2498             for (int i = 0; i < size; i++) {
2499                 if (buffer[i] == search) {
2500                     buffer[i] = replace;
2501                 }
2502             }
2503         }
2504         return this;
2505     }
2506 
2507     /**
2508      * Replaces the search string with the replace string throughout the builder.
2509      *
2510      * @param searchStr  the search string, null causes no action to occur
2511      * @param replaceStr the replace string, null is equivalent to an empty string
2512      * @return {@code this} instance.
2513      */
2514     public StrBuilder replaceAll(final String searchStr, final String replaceStr) {
2515         final int searchLen = searchStr == null ? 0 : searchStr.length();
2516         if (searchLen > 0) {
2517             final int replaceLen = replaceStr == null ? 0 : replaceStr.length();
2518             int index = indexOf(searchStr, 0);
2519             while (index >= 0) {
2520                 replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen);
2521                 index = indexOf(searchStr, index + replaceLen);
2522             }
2523         }
2524         return this;
2525     }
2526 
2527     /**
2528      * Replaces all matches within the builder with the replace string.
2529      * <p>
2530      * 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
2531      * followed by a number.
2532      * </p>
2533      *
2534      * @param matcher    the matcher to use to find the deletion, null causes no action
2535      * @param replaceStr the replace string, null is equivalent to an empty string
2536      * @return {@code this} instance.
2537      */
2538     public StrBuilder replaceAll(final StrMatcher matcher, final String replaceStr) {
2539         return replace(matcher, replaceStr, 0, size, -1);
2540     }
2541 
2542     /**
2543      * Replaces the first instance of the search character with the replace character in the builder.
2544      *
2545      * @param search  the search character
2546      * @param replace the replace character
2547      * @return {@code this} instance.
2548      */
2549     public StrBuilder replaceFirst(final char search, final char replace) {
2550         if (search != replace) {
2551             for (int i = 0; i < size; i++) {
2552                 if (buffer[i] == search) {
2553                     buffer[i] = replace;
2554                     break;
2555                 }
2556             }
2557         }
2558         return this;
2559     }
2560 
2561     /**
2562      * Replaces the first instance of the search string with the replace string.
2563      *
2564      * @param searchStr  the search string, null causes no action to occur
2565      * @param replaceStr the replace string, null is equivalent to an empty string
2566      * @return {@code this} instance.
2567      */
2568     public StrBuilder replaceFirst(final String searchStr, final String replaceStr) {
2569         final int searchLen = searchStr == null ? 0 : searchStr.length();
2570         if (searchLen > 0) {
2571             final int index = indexOf(searchStr, 0);
2572             if (index >= 0) {
2573                 final int replaceLen = replaceStr == null ? 0 : replaceStr.length();
2574                 replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen);
2575             }
2576         }
2577         return this;
2578     }
2579 
2580     /**
2581      * Replaces the first match within the builder with the replace string.
2582      * <p>
2583      * 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
2584      * number.
2585      * </p>
2586      *
2587      * @param matcher    the matcher to use to find the deletion, null causes no action
2588      * @param replaceStr the replace string, null is equivalent to an empty string
2589      * @return {@code this} instance.
2590      */
2591     public StrBuilder replaceFirst(final StrMatcher matcher, final String replaceStr) {
2592         return replace(matcher, replaceStr, 0, size, 1);
2593     }
2594 
2595     /**
2596      * Internal method to delete a range without validation.
2597      *
2598      * @param startIndex the start index, must be valid
2599      * @param endIndex   the end index (exclusive), must be valid
2600      * @param removeLen  the length to remove (endIndex - startIndex), must be valid
2601      * @param insertStr  the string to replace with, null means delete range
2602      * @param insertLen  the length of the insert string, must be valid
2603      * @throws IndexOutOfBoundsException if any index is invalid
2604      */
2605     private void replaceImpl(final int startIndex, final int endIndex, final int removeLen, final String insertStr, final int insertLen) {
2606         final int newSize = size - removeLen + insertLen;
2607         if (insertLen != removeLen) {
2608             ensureCapacity(newSize);
2609             System.arraycopy(buffer, endIndex, buffer, startIndex + insertLen, size - endIndex);
2610             size = newSize;
2611         }
2612         if (insertLen > 0) {
2613             insertStr.getChars(0, insertLen, buffer, startIndex);
2614         }
2615     }
2616 
2617     /**
2618      * Replaces within the builder using a matcher.
2619      * <p>
2620      * 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
2621      * a number.
2622      * </p>
2623      *
2624      * @param matcher      the matcher to use to find the deletion, null causes no action
2625      * @param replaceStr   the string to replace the match with, null is a delete
2626      * @param from         the start index, must be valid
2627      * @param to           the end index (exclusive), must be valid
2628      * @param replaceCount the number of times to replace, -1 for replace all
2629      * @return {@code this} instance.
2630      * @throws IndexOutOfBoundsException if any index is invalid
2631      */
2632     private StrBuilder replaceImpl(final StrMatcher matcher, final String replaceStr, final int from, int to, int replaceCount) {
2633         if (matcher == null || size == 0) {
2634             return this;
2635         }
2636         final int replaceLen = replaceStr == null ? 0 : replaceStr.length();
2637         for (int i = from; i < to && replaceCount != 0; i++) {
2638             final char[] buf = buffer;
2639             final int removeLen = matcher.isMatch(buf, i, from, to);
2640             if (removeLen > 0) {
2641                 replaceImpl(i, i + removeLen, removeLen, replaceStr, replaceLen);
2642                 to = to - removeLen + replaceLen;
2643                 i = i + replaceLen - 1;
2644                 if (replaceCount > 0) {
2645                     replaceCount--;
2646                 }
2647             }
2648         }
2649         return this;
2650     }
2651 
2652     /**
2653      * Reverses the string builder placing each character in the opposite index.
2654      *
2655      * @return {@code this} instance.
2656      */
2657     public StrBuilder reverse() {
2658         if (size == 0) {
2659             return this;
2660         }
2661 
2662         final int half = size / 2;
2663         final char[] buf = buffer;
2664         for (int leftIdx = 0, rightIdx = size - 1; leftIdx < half; leftIdx++, rightIdx--) {
2665             final char swap = buf[leftIdx];
2666             buf[leftIdx] = buf[rightIdx];
2667             buf[rightIdx] = swap;
2668         }
2669         return this;
2670     }
2671 
2672     /**
2673      * Extracts the rightmost characters from the string builder without throwing an exception.
2674      * <p>
2675      * This method extracts the right {@code length} characters from the builder. If this many characters are not available, the whole builder is returned. Thus
2676      * the returned string may be shorter than the length requested.
2677      * </p>
2678      *
2679      * @param length the number of characters to extract, negative returns empty string
2680      * @return The new string
2681      */
2682     public String rightString(final int length) {
2683         if (length <= 0) {
2684             return StringUtils.EMPTY;
2685         }
2686         if (length >= size) {
2687             return new String(buffer, 0, size);
2688         }
2689         return new String(buffer, size - length, length);
2690     }
2691 
2692     /**
2693      * Sets the character at the specified index.
2694      *
2695      * @see #charAt(int)
2696      * @see #deleteCharAt(int)
2697      * @param index the index to set
2698      * @param ch    the new character
2699      * @return {@code this} instance.
2700      * @throws IndexOutOfBoundsException if the index is invalid
2701      */
2702     public StrBuilder setCharAt(final int index, final char ch) {
2703         if (index < 0 || index >= length()) {
2704             throw new StringIndexOutOfBoundsException(index);
2705         }
2706         buffer[index] = ch;
2707         return this;
2708     }
2709 
2710     /**
2711      * Updates the length of the builder by either dropping the last characters or adding filler of Unicode zero.
2712      *
2713      * @param length the length to set to, must be zero or positive
2714      * @return {@code this} instance.
2715      * @throws IndexOutOfBoundsException if the length is negative
2716      */
2717     public StrBuilder setLength(final int length) {
2718         if (length < 0) {
2719             throw new StringIndexOutOfBoundsException(length);
2720         }
2721         if (length < size) {
2722             size = length;
2723         } else if (length > size) {
2724             ensureCapacity(length);
2725             Arrays.fill(buffer, size, length, CharUtils.NUL);
2726             size = length;
2727         }
2728         return this;
2729     }
2730 
2731     /**
2732      * Sets the text to be appended when {@link #appendNewLine() new line} is called.
2733      *
2734      * @param newLine the new line text, {@code null} means use the system default from {@link System#lineSeparator()}.
2735      * @return {@code this} instance.
2736      */
2737     public StrBuilder setNewLineText(final String newLine) {
2738         this.newLine = newLine;
2739         return this;
2740     }
2741 
2742     /**
2743      * Sets the text to be appended when null is added.
2744      *
2745      * @param nullText the null text, null means no append
2746      * @return {@code this} instance.
2747      */
2748     public StrBuilder setNullText(String nullText) {
2749         if (nullText != null && nullText.isEmpty()) {
2750             nullText = null;
2751         }
2752         this.nullText = nullText;
2753         return this;
2754     }
2755 
2756     /**
2757      * Gets the length of the string builder.
2758      * <p>
2759      * This method is the same as {@link #length()} and is provided to match the API of Collections.
2760      * </p>
2761      *
2762      * @return The length
2763      */
2764     public int size() {
2765         return size;
2766     }
2767 
2768     /**
2769      * Checks whether this builder starts with the specified string.
2770      * <p>
2771      * Note that this method handles null input quietly, unlike String.
2772      * </p>
2773      *
2774      * @param str the string to search for, null returns false
2775      * @return true if the builder starts with the string
2776      */
2777     public boolean startsWith(final String str) {
2778         if (str == null) {
2779             return false;
2780         }
2781         final int len = str.length();
2782         if (len == 0) {
2783             return true;
2784         }
2785         if (len > size) {
2786             return false;
2787         }
2788         for (int i = 0; i < len; i++) {
2789             if (buffer[i] != str.charAt(i)) {
2790                 return false;
2791             }
2792         }
2793         return true;
2794     }
2795 
2796     /**
2797      * {@inheritDoc}
2798      */
2799     @Override
2800     public CharSequence subSequence(final int startIndex, final int endIndex) {
2801         if (startIndex < 0) {
2802             throw new StringIndexOutOfBoundsException(startIndex);
2803         }
2804         if (endIndex > size) {
2805             throw new StringIndexOutOfBoundsException(endIndex);
2806         }
2807         if (startIndex > endIndex) {
2808             throw new StringIndexOutOfBoundsException(endIndex - startIndex);
2809         }
2810         return substring(startIndex, endIndex);
2811     }
2812 
2813     /**
2814      * Extracts a portion of this string builder as a string.
2815      *
2816      * @param start the start index, inclusive, must be valid
2817      * @return The new string
2818      * @throws IndexOutOfBoundsException if the index is invalid
2819      */
2820     public String substring(final int start) {
2821         return substring(start, size);
2822     }
2823 
2824     /**
2825      * Extracts a portion of this string builder as a string.
2826      * <p>
2827      * 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
2828      * StringBuffer or String.
2829      *
2830      * @param startIndex the start index, inclusive, must be valid
2831      * @param endIndex   the end index, exclusive, must be valid except that if too large it is treated as end of string
2832      * @return The new string
2833      * @throws IndexOutOfBoundsException if the index is invalid
2834      */
2835     public String substring(final int startIndex, int endIndex) {
2836         endIndex = validateRange(startIndex, endIndex);
2837         return new String(buffer, startIndex, endIndex - startIndex);
2838     }
2839 
2840     /**
2841      * Copies the builder's character array into a new character array.
2842      *
2843      * @return a new array that represents the contents of the builder
2844      */
2845     public char[] toCharArray() {
2846         return size == 0 ? ArrayUtils.EMPTY_CHAR_ARRAY : Arrays.copyOf(buffer, size);
2847     }
2848 
2849     /**
2850      * Copies part of the builder's character array into a new character array.
2851      *
2852      * @param startIndex the start index, inclusive, must be valid
2853      * @param endIndex   the end index, exclusive, must be valid except that if too large it is treated as end of string
2854      * @return a new array that holds part of the contents of the builder
2855      * @throws IndexOutOfBoundsException if startIndex is invalid, or if endIndex is invalid (but endIndex greater than size is valid)
2856      */
2857     public char[] toCharArray(final int startIndex, int endIndex) {
2858         endIndex = validateRange(startIndex, endIndex);
2859         final int len = endIndex - startIndex;
2860         if (len == 0) {
2861             return ArrayUtils.EMPTY_CHAR_ARRAY;
2862         }
2863         final char[] chars = new char[len];
2864         System.arraycopy(buffer, startIndex, chars, 0, len);
2865         return chars;
2866     }
2867 
2868     /**
2869      * Gets a String version of the string builder, creating a new instance each time the method is called.
2870      * <p>
2871      * Note that unlike StringBuffer, the string version returned is independent of the string builder.
2872      * </p>
2873      *
2874      * @return The builder as a String
2875      */
2876     @Override
2877     public String toString() {
2878         return new String(buffer, 0, size);
2879     }
2880 
2881     /**
2882      * Gets a StringBuffer version of the string builder, creating a new instance each time the method is called.
2883      *
2884      * @return The builder as a StringBuffer
2885      */
2886     public StringBuffer toStringBuffer() {
2887         return new StringBuffer(size).append(buffer, 0, size);
2888     }
2889 
2890     /**
2891      * Gets a StringBuilder version of the string builder, creating a new instance each time the method is called.
2892      *
2893      * @return The builder as a StringBuilder
2894      */
2895     public StringBuilder toStringBuilder() {
2896         return new StringBuilder(size).append(buffer, 0, size);
2897     }
2898 
2899     /**
2900      * Trims the builder by removing characters less than or equal to a space from the beginning and end.
2901      *
2902      * @return {@code this} instance.
2903      */
2904     public StrBuilder trim() {
2905         if (size == 0) {
2906             return this;
2907         }
2908         int len = size;
2909         final char[] buf = buffer;
2910         int pos = 0;
2911         while (pos < len && buf[pos] <= ' ') {
2912             pos++;
2913         }
2914         while (pos < len && buf[len - 1] <= ' ') {
2915             len--;
2916         }
2917         if (len < size) {
2918             delete(len, size);
2919         }
2920         if (pos > 0) {
2921             delete(0, pos);
2922         }
2923         return this;
2924     }
2925 
2926     /**
2927      * Validates parameters defining a single index in the builder.
2928      *
2929      * @param index the index, must be valid
2930      * @throws IndexOutOfBoundsException if the index is invalid
2931      */
2932     protected void validateIndex(final int index) {
2933         if (index < 0 || index > size) {
2934             throw new StringIndexOutOfBoundsException(index);
2935         }
2936     }
2937 
2938     /**
2939      * Validates parameters defining a range of the builder.
2940      *
2941      * @param startIndex the start index, inclusive, must be valid
2942      * @param endIndex   the end index, exclusive, must be valid except that if too large it is treated as end of string
2943      * @return The new string
2944      * @throws IndexOutOfBoundsException if the index is invalid
2945      */
2946     protected int validateRange(final int startIndex, int endIndex) {
2947         if (startIndex < 0) {
2948             throw new StringIndexOutOfBoundsException(startIndex);
2949         }
2950         if (endIndex > size) {
2951             endIndex = size;
2952         }
2953         if (startIndex > endIndex) {
2954             throw new StringIndexOutOfBoundsException("end < start");
2955         }
2956         return endIndex;
2957     }
2958 
2959 }