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