    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}