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