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