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