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