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