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