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